--#selene: allow(shadowing)
-- Redon Tech Emergency Vehicle Creator, MIT License
local root = script.Parent.Parent.Parent.Parent.Parent.Parent

local Fusion = require(root.Packages.fusion)
local RedonUI = require(root.Packages["redon-ui"])
local types = require(root.Plugin.types)
local popup = require(root.Plugin.Components.popup)
local chassisHandler = require(root.Plugin.chassisHandler)
local assets = require(root.Plugin.assets)
local log = require(root.Plugin.log)

local columnHeader = require(script.Parent.columnHeader)
local column = require(script.Parent.column)
local components = {
	columnHeader = columnHeader,
	column = column,
}

local SPRING_SPEED = 25
local SPRING_DAMPING = 1
--[=[
	flashers.sections
	Creates the sections for the flashers editor
]=]
return function(
	baseScope: types.Scope,
	props: {
		colors: Fusion.Value<{ chassisHandler.color }>,
		currentColor: Fusion.Value<number>,
		playing: Fusion.Value<boolean>,
		drawing: Fusion.Value<number>,
		size: Fusion.Value<Vector2>,
		temporarlyPause: () -> () -> (),
		locked: Fusion.Value<boolean>,
		holdingShift: Fusion.Value<boolean>,
		sections: Fusion.Value<{ types.flasherSectionState }>,
		updateCurrentConfiguration: () -> (),
		addSection: (atPoint: number) -> (),
	}
)
	local scope = baseScope:innerScope(components)
	local currentTheme = RedonUI.theme.theme:now()
	local lockedTo: Fusion.Value<{ section: number, column: number }?> = scope:Value(nil)

	scope:Observer(props.locked):onChange(function()
		if scope.peek(props.locked) == false then
			lockedTo:set(nil)
		end
	end)

	return scope:ForPairs(
		props.sections,
		function(_, scope: typeof(scope), key: number, value: types.flasherSectionState)
			log.debug("Creating section", key, value)
			local position = scope:Value(Vector2.one)
			local contentSize = scope:Value(Vector2.one)
			local canvasSize = scope:Value(Vector2.one)
			local canvasPosition = scope:Value(Vector2.zero)
			local currentlyHovering = scope:Value(1)
			local positionsScope = scope:innerScope()
			local columnPositions: Fusion.Value<{ [number]: { scope: typeof(positionsScope), value: Fusion.Value<Vector2> } }> =
				scope:Value({})
			local function addPosition(position: number)
				local tempScope = positionsScope:innerScope()
				local tempValue = tempScope:Value(Vector2.one)
				local previousPositions = scope.peek(columnPositions)
				local previousScope = if previousPositions[position] ~= nil
					then previousPositions[position].scope
					else nil
				previousPositions[position] = {
					scope = tempScope,
					value = tempValue,
				}
				columnPositions:set(previousPositions)
				if previousScope ~= nil then
					previousScope:doCleanup()
				end
			end
			for i = 1, #scope.peek(value.columns) do
				addPosition(i)
			end
			local hoverPosition = scope:Computed(function(use)
				local positionData = use(columnPositions)[use(currentlyHovering)]
				return if positionData ~= nil
					then math.clamp(
						use(positionData.value).X - use(position).X - 0.0133689840 * use(props.size).X,
						0,
						use(contentSize).X
					)
					else 0
			end)

			scope:Observer(value.rowCount):onChange(function()
				if scope.peek(props.playing) == true then
					return
				end
				local currentRowCount = scope.peek(value.rowCount)
				if scope.peek(value.currentRow) > currentRowCount then
					value.currentRow:set(1)
				end
			end)

			local function propagateNameChange(columnData: types.flasherColumnDataState, columnKey: number)
				if columnData.currentName == nil then
					return
				end
				local newName = scope.peek(columnData.lightName)
				local pattern = scope.peek(newName):gsub("%d+$", "")
				local originalNumber = tonumber(newName:match("%d+$"))
				if originalNumber == nil then
					return
				end
				local originalPattern = scope.peek(columnData.currentName):gsub("%d+$", "")

				if
					value.nameTemplate == nil
					or value.nameTemplate.originalPosition <= columnKey
					or value.nameTemplate.pattern == originalPattern
				then
					value.nameTemplate = {
						pattern = pattern,
						originalPosition = columnKey,
						originalNumber = originalNumber,
					}
				end

				for columnId, column in scope.peek(value.columns) do
					if columnId < columnKey then
						continue
					end
					local name = scope.peek(column.lightName)
					if value.nameTemplate ~= nil then
						log.debug(
							value.nameTemplate.originalPosition,
							columnKey,
							columnId,
							originalPattern,
							columnData.currentName
						)
						if
							value.nameTemplate.originalPosition > columnKey
							and (columnId >= value.nameTemplate.originalPosition or not name:match(originalPattern))
						then
							log.debug("Position or match not met")
							continue
						elseif not name:match(originalPattern) then
							log.debug("Not matching")
							continue
						end
					end
					log.debug("Setting name", pattern, originalNumber, columnId, columnKey)
					column.lightName:set(pattern .. originalNumber + columnId - columnKey)

					if column.currentName ~= nil then
						column.currentName:set(scope.peek(column.lightName))
					end
				end
				columnData.currentName:set(newName)
			end

			local waitTimeText = scope:Value(tostring(scope.peek(value.waitTime)))
			return key,
				scope:base {
					Name = key,
					BackgroundColor3 = currentTheme.colors.mantle,
					Size = UDim2.fromScale(0, 0.9259259259),
					CornerRadius = scope:Computed(function(use)
						return UDim.new(0, 0.0171428571 * use(props.size).Y) -- I shouldn't have to do this
					end),
					LayoutOrder = key,
					AutomaticSize = Enum.AutomaticSize.X,
					[Fusion.Out "AbsolutePosition"] = position :: unknown,

					[Fusion.Children] = Fusion.Child {
						scope:New("UIPadding") {
							PaddingTop = UDim.new(0.0285714286, 0),
							PaddingBottom = UDim.new(0.0285714286, 0),
							PaddingLeft = scope:Computed(function(use)
								return UDim.new(0, 0.0133689840 * use(props.size).X)
							end),
							PaddingRight = scope:Computed(function(use)
								return UDim.new(0, 0.0133689840 * use(props.size).X)
							end),
						},

						scope:base {
							Name = "Controls",
							Size = UDim2.fromScale(1, 0.0571428571),
							AutomaticSize = Enum.AutomaticSize.X,
							BackgroundTransparency = 1,

							[Fusion.Children] = {
								scope:New("UIListLayout") {
									Padding = scope:Computed(function(use)
										return UDim.new(0, 0.0080213904 * use(props.size).X)
									end),
									FillDirection = Enum.FillDirection.Horizontal,
									HorizontalAlignment = Enum.HorizontalAlignment.Center,
									SortOrder = Enum.SortOrder.LayoutOrder,
								},

								scope:iconButton {
									Size = scope:Computed(function(use)
										return UDim2.new(0, 0.0267379679 * use(props.size).X, 1, 0)
									end),
									LayoutOrder = 1,
									CornerRadius = UDim.new(0.2, 0),
									Border = 2,
									Reactive = true,
									Image = assets.images.redonUI.remove,
									BackgroundColor3 = currentTheme.colors.mantle,
									ImageColor3 = currentTheme.colors.text,

									[Fusion.OnEvent "Activated"] = function()
										popup:addPopup(scope, {
											title = "Remove Section",
											description = `Are you sure you want to delete section <b>{key}</b>?\n<b>All data will be lost.</b>`,
											actions = {
												{
													text = "Cancel",
													type = "primary",
													key = 1,
													callback = function(newPopup)
														popup:removePopup(newPopup)
													end,
													keybind = Enum.KeyCode.Escape,
												},
												{
													text = "Delete",
													type = "danger",
													key = 2,
													callback = function(newPopup)
														local unpause = props.temporarlyPause()
														popup:removePopup(newPopup)
														local currentSections = scope.peek(props.sections)
														table.remove(currentSections, key)
														props.sections:set(currentSections)
														props.updateCurrentConfiguration()
														unpause()
													end,
													keybind = Enum.KeyCode.Return,
												},
											},
										})
									end,
								},

								scope:textBox {
									Size = scope:Computed(function(use)
										return UDim2.new(0, 0.0534759358 * use(props.size).X, 1, 0)
									end),
									LayoutOrder = 2,
									CornerRadius = UDim.new(0.2, 0),
									Border = 1,
									Text = waitTimeText,
									[Fusion.Out "Text"] = waitTimeText :: unknown,
									BackgroundColor3 = currentTheme.colors.mantle,
									[Fusion.OnEvent "FocusLost"] = function()
										local unpause = props.temporarlyPause()
										value.waitTime:set(tonumber(scope.peek(waitTimeText)) or 0.05)
										waitTimeText:set(tostring(scope.peek(value.waitTime)))
										props.updateCurrentConfiguration()
										unpause()
									end,
								},

								scope:iconButton {
									Size = scope:Computed(function(use)
										return UDim2.new(0, 0.0267379679 * use(props.size).X, 1, 0)
									end),
									LayoutOrder = 3,
									CornerRadius = UDim.new(0.2, 0),
									Border = 2,
									Reactive = true,
									Image = assets.images.redonUI.add,
									BackgroundColor3 = currentTheme.colors.mantle,
									ImageColor3 = currentTheme.colors.text,

									[Fusion.OnEvent "Activated"] = function()
										props.addSection(key + 1)
									end,
								},
							},
						},

						scope:base {
							Name = "Headers",
							Size = UDim2.fromScale(1, 0.0342857143),
							Position = UDim2.fromScale(0.5, 0.0857142857),
							AnchorPoint = Vector2.new(0.5, 0),
							-- AutomaticSize = Enum.AutomaticSize.X,
							BackgroundTransparency = 1,
							ZIndex = 3,

							[Fusion.Children] = scope:ForPairs(
								value.columns,
								function(use, scope: typeof(scope), columnKey: number, columnData)
									return columnKey,
										scope:columnHeader {
											use = use,
											columnKey = columnKey,
											columnData = columnData,
											columnPositions = columnPositions,
											colors = props.colors,
											playing = props.playing,
											size = props.size,
											position = position,
											section = value,
											updateCurrentConfiguration = props.updateCurrentConfiguration,
											propagateNameChange = propagateNameChange,
										}
								end
							),
						},

						scope:base {
							Size = scope:Computed(function(use)
								return UDim2.new(
									0,
									use(contentSize).X - (0.0106951872 * use(props.size).X),
									0.0114285714,
									0
								)
							end),
							AnchorPoint = Vector2.new(0.5, 0),
							Position = UDim2.fromScale(0.5, 0.1428571429),
							BackgroundColor3 = currentTheme.colors.base,
							CornerRadius = UDim.new(1, 0),
						},

						scope:base {
							Name = "controls",
							Size = scope:Computed(function(use)
								return UDim2.new(0, 0.0401069519 * use(props.size).X, 0.04, 0)
							end),
							Position = scope:Spring(
								scope:Computed(function(use)
									return UDim2.new(0, use(hoverPosition), 0.1291428571, 0) -- 0.1285714286
								end),
								SPRING_SPEED,
								SPRING_DAMPING
							),
							BackgroundColor3 = currentTheme.colors.mantle,

							[Fusion.Children] = {
								scope:New("UIListLayout") {
									Padding = UDim.new(0.1333333333, 0),
									FillDirection = Enum.FillDirection.Horizontal,
									HorizontalAlignment = Enum.HorizontalAlignment.Center,
									VerticalAlignment = Enum.VerticalAlignment.Center,
									SortOrder = Enum.SortOrder.LayoutOrder,
								},

								scope:iconButton {
									Size = UDim2.fromScale(0.4, 0.8571428571),
									BackgroundColor3 = currentTheme.colors.crust,
									CornerRadius = UDim.new(0.1666666667, 0),
									Image = assets.images.redonUI.remove,
									Border = 1,
									Reactive = true,

									[Fusion.OnEvent "Activated"] = function()
										if #scope.peek(value.columns) == 1 then
											log.warn("Cannot remove last column")
											return
										end
										local deleting = scope.peek(currentlyHovering)

										local function remove()
											currentlyHovering:set(
												math.clamp(
													deleting,
													if deleting == 1 then 2 else 1,
													#scope.peek(value.columns) - 1
												)
											)
											local currentColumns = scope.peek(value.columns)
											table.remove(currentColumns, deleting)
											value.columns:set(currentColumns)
											props.updateCurrentConfiguration()
										end

										if scope.peek(props.holdingShift) then
											remove()
											return
										end

										popup:addPopup(scope, {
											title = "Remove Column",
											description = `Are you sure you want to delete column <b>{deleting}</b>?\n<b>All data will be lost.</b>`,
											actions = {
												{
													text = "Cancel",
													type = "primary",
													key = 1,
													callback = function(newPopup)
														popup:removePopup(newPopup)
													end,
													keybind = Enum.KeyCode.Escape,
												},
												{
													text = "Delete",
													type = "danger",
													key = 2,
													callback = function(newPopup)
														popup:removePopup(newPopup)
														remove()
													end,
													keybind = Enum.KeyCode.Return,
												},
											},
										})
									end,
								},

								scope:iconButton {
									Size = UDim2.fromScale(0.4, 0.8571428571),
									LayoutOrder = 2,
									BackgroundColor3 = currentTheme.colors.crust,
									CornerRadius = UDim.new(0.1666666667, 0),
									Image = assets.images.redonUI.add,
									Border = 1,
									Reactive = true,

									[Fusion.OnEvent "Activated"] = function()
										local adding = scope.peek(currentlyHovering)
										local currentColumns = scope.peek(value.columns)
										local rows = {}
										for _ = 1, scope.peek(value.rowCount) do
											table.insert(rows, 0)
										end

										local lightName = `Light {adding + 1}`
										local addingNumber = tonumber(
											scope.peek(currentColumns[adding].lightName):match("%d+$")
										) or adding
										local pattern = scope.peek(currentColumns[adding].lightName):gsub("%d+$", "")
										lightName = pattern .. addingNumber + 1

										table.insert(currentColumns, adding + 1, {
											lightName = scope:Value(lightName),
											color = scope:Value(currentTheme.colors.base),
											rows = scope:Value(rows),
										})
										value.columns:set(currentColumns)
										propagateNameChange(currentColumns[adding + 1], adding + 1)
										if columnPositions[adding + 1] == nil then
											addPosition(adding + 1)
										end
										props.updateCurrentConfiguration()
										task.delay(1 / 16, function()
											currentlyHovering:set(adding + 1)
										end)
									end,
								},
							},
						},

						scope:base {
							ClassName = "ScrollingFrame",
							Name = "Columns",
							Size = UDim2.fromScale(1, 0.8285714286),
							AutomaticSize = Enum.AutomaticSize.X,
							Position = UDim2.fromScale(0, 0.1771428571),
							BackgroundTransparency = 1,
							CanvasSize = UDim2.new(),
							ScrollBarThickness = 3,
							ScrollBarImageColor3 = currentTheme.colors.text,
							TopImage = "rbxasset://textures/ui/Scroll/scroll-middle.png",
							BottomImage = "rbxasset://textures/ui/Scroll/scroll-middle.png",
							AutomaticCanvasSize = Enum.AutomaticSize.Y,
							[Fusion.Out "CanvasPosition"] = canvasPosition :: unknown,
							[Fusion.Out "AbsoluteCanvasSize"] = canvasSize :: unknown,
							ZIndex = 2,

							[Fusion.Children] = Fusion.Child {
								scope:New("UIListLayout") {
									Padding = scope:Computed(function(use)
										return UDim.new(0, 0.0053475936 * use(props.size).X)
									end),
									FillDirection = Enum.FillDirection.Horizontal,
									HorizontalAlignment = Enum.HorizontalAlignment.Center,
									SortOrder = Enum.SortOrder.LayoutOrder,
									[Fusion.Out "AbsoluteContentSize"] = contentSize :: unknown,
								},

								scope:ForPairs(
									value.columns,
									function(_, scope: typeof(scope), columnKey: number, columnData)
										return columnKey,
											scope:column {
												columnKey = columnKey,
												columnData = columnData,
												sectionKey = key,
												currentlyHovering = currentlyHovering,
												columnPositions = columnPositions,
												drawing = props.drawing,
												size = props.size,
												updateCurrentConfiguration = props.updateCurrentConfiguration,
												locked = props.locked,
												currentColor = props.currentColor,
												colors = props.colors,
												lockedTo = lockedTo,
											}
									end
								),
							},
						},

						scope:base {
							ClassName = "ScrollingFrame",
							Name = "ColumnIndicators",
							Size = UDim2.fromScale(1.05, 0.8285714286),
							Position = UDim2.fromScale(0.5, 0.1771428571),
							AnchorPoint = Vector2.new(0.5, 0),
							BackgroundTransparency = 1,
							AutomaticCanvasSize = Enum.AutomaticSize.Y,
							CanvasPosition = canvasPosition,
							ScrollingEnabled = false,
							ScrollBarThickness = 0,
							ClipsDescendants = scope:Computed(function(use)
								return if use(value.currentRow) == 1 and use(canvasPosition) == Vector2.zero
									then false
									else true
							end),

							[Fusion.Children] = {
								scope:base {
									BackgroundTransparency = 1,
									Size = scope:Computed(function(use)
										return UDim2.new(0, 10, 0, use(canvasSize).Y)
									end),
								},

								scope:base {
									Name = "indicator",
									Size = scope:Computed(function(use)
										return UDim2.new(
											0,
											use(contentSize).X + (0.0053475936 * use(props.size).X),
											0.0597014925,
											0
										)
									end),
									Position = scope:Computed(function(use)
										local currentRow = use(value.currentRow) - 1
										return UDim2.fromScale(
											0.5,
											(currentRow * 0.0447761194) + (currentRow * 0.0114285714) - 0.0074626866
										)
									end),
									AnchorPoint = Vector2.new(0.5, 0),
									BackgroundColor3 = scope:Computed(function(use)
										return if use(props.playing) == true
											then currentTheme.colors.lavender
											else currentTheme.colors.crust
									end),
									BackgroundTransparency = scope:Computed(function(use)
										return if use(props.playing) == true then 0.5 else 0
									end),
									CornerRadius = UDim.new(0.175, 0),
								},
							},
						},

						scope:base {
							ClassName = "ScrollingFrame",
							Name = "ColumnControls",
							Size = UDim2.fromScale(1, 0.8285714286),
							Position = UDim2.fromScale(0, 0.1771428571),
							BackgroundTransparency = 1,
							AutomaticCanvasSize = Enum.AutomaticSize.Y,
							CanvasPosition = canvasPosition,
							ScrollingEnabled = false,
							ScrollBarThickness = 0,

							[Fusion.Children] = {
								scope:base {
									BackgroundTransparency = 1,
									Size = scope:Computed(function(use)
										return UDim2.new(0, 10, 0, use(canvasSize).Y)
									end),
								},

								scope:base {
									Name = "controls",
									Size = scope:Computed(function(use)
										return UDim2.new(0, 0.0401069519 * use(props.size).X, 1, 0)
									end),
									Position = scope:Spring(
										scope:Computed(function(use)
											return UDim2.new(0, use(hoverPosition), 0, 0)
										end),
										SPRING_SPEED,
										SPRING_DAMPING
									),
									BackgroundTransparency = 1,

									[Fusion.Children] = Fusion.Child {
										scope:New("UIListLayout") {
											Padding = UDim.new(0.0114285714, 0),
											HorizontalAlignment = Enum.HorizontalAlignment.Center,
											SortOrder = Enum.SortOrder.LayoutOrder,
										},

										scope:Computed(function(use, scope: typeof(scope))
											return scope:ForPairs(
												table.create(use(value.rowCount), true),
												function(_, scope: typeof(scope), key: number, _)
													return key,
														scope:base {
															Name = key,
															Size = UDim2.fromScale(1, 0.0447761194),
															BackgroundTransparency = 1,
															LayoutOrder = key,
														}
												end
											)
										end),

										scope:iconButton {
											Size = UDim2.fromScale(0.4, 0.0447761194),
											LayoutOrder = 4000,
											BackgroundColor3 = currentTheme.colors.crust,
											CornerRadius = UDim.new(0.1666666667, 0),
											Image = assets.images.redonUI.remove,
											Border = 1,
											Reactive = true,

											[Fusion.OnEvent "Activated"] = function()
												if scope.peek(value.rowCount) == 1 then
													log.warn("Cannot remove last row")
													return
												end
												local deleting = scope.peek(value.rowCount)

												local function remove()
													value.rowCount:set(deleting - 1)

													for _, column in scope.peek(value.columns) do
														local currentRows = scope.peek(column.rows)
														table.remove(currentRows)
														column.rows:set(currentRows)
													end

													props.updateCurrentConfiguration()
												end

												if scope.peek(props.holdingShift) then
													remove()
													return
												end

												popup:addPopup(scope, {
													title = "Remove Column",
													description = `Are you sure you want to delete row <b>{deleting}</b>?\n<b>All data will be lost.</b>`,
													actions = {
														{
															text = "Cancel",
															type = "primary",
															key = 1,
															callback = function(newPopup)
																popup:removePopup(newPopup)
															end,
															keybind = Enum.KeyCode.Escape,
														},
														{
															text = "Delete",
															type = "danger",
															key = 2,
															callback = function(newPopup)
																popup:removePopup(newPopup)
																remove()
															end,
															keybind = Enum.KeyCode.Return,
														},
													},
												})
											end,
										},

										scope:iconButton {
											Size = UDim2.fromScale(0.4, 0.0447761194),
											LayoutOrder = 4001,
											BackgroundColor3 = currentTheme.colors.crust,
											CornerRadius = UDim.new(0.1666666667, 0),
											Image = assets.images.redonUI.add,
											Border = 1,
											Reactive = true,

											[Fusion.OnEvent "Activated"] = function()
												local currentRowCount = scope.peek(value.rowCount)
												if scope.peek(props.holdingShift) then
													currentRowCount += 5
												else
													currentRowCount += 1
												end
												value.rowCount:set(currentRowCount)

												for _, column in scope.peek(value.columns) do
													local currentRows = scope.peek(column.rows)
													while #currentRows < currentRowCount do
														table.insert(currentRows, 0)
													end
													column.rows:set(currentRows)
												end

												props.updateCurrentConfiguration()
											end,
										},
									},
								},
							},
						},
					},
				}
		end
	)
end


--#selene: allow(shadowing)
-- Redon Tech Emergency Vehicle Creator, MIT License
local root = script.Parent.Parent.Parent.Parent.Parent.Parent

local Fusion = require(root.Packages.fusion)
local RedonUI = require(root.Packages["redon-ui"])
local types = require(root.Plugin.types)
local chassisHandler = require(root.Plugin.chassisHandler)
local assets = require(root.Plugin.assets)
local utils = require(root.Plugin.utils)

--[[
	Rotators
	Creates the rotators screen for the main app
]]
return function(
	scope: types.Scope,
	props: {
		key: number,
		angle: types.rotatorDataState,
		rotator: types.rotatorSectionState,
		playing: Fusion.Value<boolean>,
		colors: Fusion.Value<{ chassisHandler.color }>,
		updateCurrentConfiguration: () -> (),
		firstScope: types.Scope,
		dataSize: Fusion.Value<Vector2>,
	}
): Fusion.Child
	local currentTheme = RedonUI.theme.theme:now()

	local controlSize = scope:Computed(function(use)
		return UDim2.new(1, 0, 0, 0.1010101010 * use(props.dataSize).Y)
	end)
	local cornerRadius = scope:Computed(function(use)
		return UDim.new(0, 0.0202020202 * use(props.dataSize).Y)
	end)
	local baseDropdown = scope:dropdown {
		Size = controlSize,
		BackgroundColor3 = currentTheme.colors.crust,
		CornerRadius = cornerRadius,
		Border = 1,
		Text = props.angle.type :: any,
		TextXAlignment = Enum.TextXAlignment.Left,
		LayoutOrder = 1,
		DropdownHeight = 150,
		Options = {
			"Angle",
			"Infinite",
			"Wait",
		},
		OnOptionSelected = function(_, newType)
			if newType == "Wait" then
				props.angle.color = nil
				props.angle.angle = nil
				props.angle.velocity = nil
				props.angle.time = if props.angle.time ~= nil then props.angle.time else props.firstScope:Value(0.1)
			elseif newType == "Infinite" then
				props.angle.angle = nil
				props.angle.time = nil
				props.angle.color = if props.angle.color ~= nil then props.angle.color else props.firstScope:Value(1)
				props.angle.velocity = if props.angle.velocity ~= nil
					then props.angle.velocity
					else props.firstScope:Value(0.1)
			elseif newType == "Angle" then
				props.angle.time = nil
				props.angle.angle = if props.angle.angle ~= nil then props.angle.angle else props.firstScope:Value(90)
				props.angle.color = if props.angle.color ~= nil then props.angle.color else props.firstScope:Value(1)
				props.angle.velocity = if props.angle.velocity ~= nil
					then props.angle.velocity
					else props.firstScope:Value(0.1)
			end

			props.angle.type:set(newType :: "Angle" | "Infinite" | "Wait")
			props.updateCurrentConfiguration()
		end,
	}
	local baseDropdownFrame = baseDropdown[2] :: Frame
	baseDropdownFrame.LayoutOrder = 2
	local baseControls: { Fusion.Child } = {
		baseDropdown,
	}

	local controls = scope:Computed(function(use, scope: typeof(scope))
		local controls: { Fusion.Child } = baseControls
		local currentType = use(props.angle.type)

		if currentType == "Angle" or currentType == "Infinite" then
			if props.angle.color ~= nil then
				local colorDropdown = scope:dropdown {
					Size = controlSize,
					BackgroundColor3 = currentTheme.colors.crust,
					CornerRadius = cornerRadius,
					Border = 1,
					Text = scope:Computed(function(use)
						local colorId = use(props.angle.color)
						return if colorId == 0 then "None" else use(props.colors)[colorId].name
					end),
					TextXAlignment = Enum.TextXAlignment.Left,
					LayoutOrder = 3,
					DropdownHeight = 150,
					Options = scope:Computed(function(use)
						local newColors: { string } = {}
						for colorId, color in pairs(use(props.colors)) do
							table.insert(newColors, colorId, color.name)
						end
						table.insert(newColors, 1, "None")
						return newColors
					end),
					OptionOverrides = scope:Computed(function(use)
						local textColors = {}
						for colorId, color in pairs(use(props.colors)) do
							textColors[colorId] = {
								TextColor3 = utils.getColorByName(color.name, currentTheme.colors.text),
							}
						end
						table.insert(textColors, 1, {
							TextColor3 = currentTheme.colors.text,
						})
						return textColors :: any
					end),
					TextColor3 = scope:Computed(function(use)
						local colorId = use(props.angle.color)
						return if colorId == 0
							then currentTheme.colors.text
							else utils.getColorByName(use(props.colors)[colorId].name, currentTheme.colors.text)
					end),
					OnOptionSelected = function(colorId: number)
						props.angle.color:set(colorId - 1)
						props.updateCurrentConfiguration()
					end,
				}
				local colorDropdownFrame = colorDropdown[2] :: Frame
				colorDropdownFrame.LayoutOrder = 4
				table.insert(controls, colorDropdown)
			end
			if props.angle.velocity ~= nil then
				local currentText = scope:Value(tostring(scope.peek(props.angle.velocity)))
				table.insert(
					controls,
					scope:textBox {
						Size = controlSize,
						BackgroundColor3 = currentTheme.colors.crust,
						CornerRadius = UDim.new(0.2, 0),
						Border = 1,
						Text = currentText,
						[Fusion.Out "Text"] = currentText :: unknown,
						PlaceholderText = "Velocity",
						PlaceholderColor3 = currentTheme.colors.subtext0,
						LayoutOrder = 7,
						[Fusion.OnEvent "FocusLost"] = function()
							props.angle.velocity:set(tonumber(scope.peek(currentText)) or 0)
							currentText:set(tostring(scope.peek(props.angle.velocity)))
							props.updateCurrentConfiguration()
						end,
					}
				)
			end
		elseif currentType == "Wait" then
			if props.angle.time ~= nil then
				local currentText = scope:Value(tostring(scope.peek(props.angle.time)))
				table.insert(
					controls,
					scope:textBox {
						Size = controlSize,
						BackgroundColor3 = currentTheme.colors.crust,
						CornerRadius = UDim.new(0.2, 0),
						Border = 1,
						Text = currentText,
						[Fusion.Out "Text"] = currentText :: unknown,
						PlaceholderText = "Wait Time",
						PlaceholderColor3 = currentTheme.colors.subtext0,
						LayoutOrder = 7,
						[Fusion.OnEvent "FocusLost"] = function()
							props.angle.time:set(tonumber(scope.peek(currentText)) or 0)
							currentText:set(tostring(scope.peek(props.angle.time)))
							props.updateCurrentConfiguration()
						end,
					}
				)
			end
		end

		if currentType == "Angle" then
			if props.angle.angle ~= nil then
				local currentText = scope:Value(tostring(scope.peek(props.angle.angle)))
				table.insert(
					controls,
					scope:textBox {
						Size = controlSize,
						BackgroundColor3 = currentTheme.colors.crust,
						CornerRadius = UDim.new(0.2, 0),
						Border = 1,
						Text = currentText,
						[Fusion.Out "Text"] = currentText :: unknown,
						PlaceholderText = "Angle",
						PlaceholderColor3 = currentTheme.colors.subtext0,
						LayoutOrder = 6,
						[Fusion.OnEvent "FocusLost"] = function()
							props.angle.angle:set(tonumber(scope.peek(currentText)) or 0)
							currentText:set(tostring(scope.peek(props.angle.angle)))
							props.updateCurrentConfiguration()
						end,
					}
				)
			end
		end

		return controls
	end)

	return scope:base {
		Name = props.key,
		Size = UDim2.fromScale(0.5357142857, 0),
		BackgroundTransparency = 1,
		LayoutOrder = props.key,
		AutomaticSize = Enum.AutomaticSize.Y,

		[Fusion.Children] = {
			scope:base {
				ClassName = "ImageLabel",
				Size = UDim2.fromScale(0.1333333333, 1),
				Position = UDim2.fromScale(-0.0666666667, 0),
				AnchorPoint = Vector2.new(1, 0),
				BackgroundTransparency = 1,
				Image = assets.images.elsCreator.box,
				ResampleMode = Enum.ResamplerMode.Pixelated,
				ScaleType = Enum.ScaleType.Slice,
				SliceCenter = Rect.new(2, 2, 18, 33),

				[Fusion.Children] = {
					scope:New("UIGradient") {
						Name = "UIGradient",
						Color = ColorSequence.new({
							ColorSequenceKeypoint.new(0, currentTheme.colors.blue),
							ColorSequenceKeypoint.new(0.001, currentTheme.colors.text),
							ColorSequenceKeypoint.new(1, currentTheme.colors.text),
						}),
						Offset = scope:Computed(function(use)
							local percent = 0
							if use(props.playing) == true then
								if use(props.rotator.currentAngle) == props.key then
									if use(props.angle.type) == "Infinite" then
										percent = 1
									else
										percent = use(props.rotator.currentPercentage)
									end
								elseif use(props.rotator.currentAngle) > props.key then
									percent = 1
								end
							end
							return Vector2.new(0, percent)
						end),
						Rotation = 90,
					},
				},
			},

			scope:base {
				Name = "Controls",
				Size = UDim2.fromScale(1, 0),
				Position = UDim2.fromScale(0, 0),
				BackgroundTransparency = 1,
				AutomaticSize = Enum.AutomaticSize.Y,

				[Fusion.Children] = Fusion.Child {
					scope:New("UIListLayout") {
						Padding = scope:Computed(function(use)
							return UDim.new(0, 0.0202020202 * use(props.dataSize).Y)
						end),
						FillDirection = Enum.FillDirection.Vertical,
						HorizontalAlignment = Enum.HorizontalAlignment.Center,
						VerticalAlignment = Enum.VerticalAlignment.Top,
						SortOrder = Enum.SortOrder.LayoutOrder,
					},

					controls,
				},
			},
		},
	}
end


--#selene: allow(shadowing)
-- Redon Tech Emergency Vehicle Creator, MIT License
local root = script.Parent.Parent.Parent.Parent.Parent

local Fusion = require(root.Packages.fusion)
local RedonUI = require(root.Packages["redon-ui"])
local types = require(root.Plugin.types)
local popup = require(root.Plugin.Components.popup)
local chassisHandler = require(root.Plugin.chassisHandler)
local assets = require(root.Plugin.assets)
local log = require(root.Plugin.log)
local utils = require(root.Plugin.utils)
local RunService = game:GetService("RunService")

local rotator = require(script.rotator)
local components = {
	rotator = rotator,
}

type props = {
	UnsavedChanges: Fusion.Value<boolean>,
	Enabled: Fusion.UsedAs<boolean>,
	Mode: Fusion.Value<types.mode>,
	CurrentPanel: Fusion.Value<types.mainPanels>,
	CurrentPage: Fusion.Value<types.pages?>,
	CurrentVehicle: Fusion.Value<Model | string?>,
	CurrentPattern: Fusion.Value<types.selectedPattern?>,
}

--[[
	Rotators
	Creates the rotators screen for the main app
]]
return function(baseScope: types.Scope, props: props): Fusion.Child
	local currentTheme = RedonUI.theme.theme:now()
	local scope = baseScope:innerScope(components)
	local firstScope = scope:innerScope()

	local currentConfiguration: chassisHandler.chassisConfiguration? = nil
	local colors: Fusion.Value<{ chassisHandler.color }> = scope:Value(chassisHandler.defaults.colors)
	local playing = scope:Value(false)
	local function temporarlyPause()
		local wasPlaying = scope.peek(playing)
		playing:set(false)
		return function()
			playing:set(wasPlaying)
		end
	end
	local holdingShift = scope:Value(false) -- This is used to skip certain popups
	local rotators: Fusion.Value<{ types.rotatorSectionState }> = scope:Value({})

	local function updateCurrentConfiguration()
		local currentPattern = scope.peek(props.CurrentPattern)
		if currentPattern ~= nil then
			local assembledRotators: { types.rotatorSection } = {}
			for _, rotator in scope.peek(rotators) do
				local assembledData: { types.rotatorData } = {}
				for _, angle in scope.peek(rotator.data) do
					if scope.peek(angle.type) == "Angle" then
						table.insert(assembledData, {
							type = "Angle",
							color = scope.peek(angle.color),
							angle = scope.peek(angle.angle),
							velocity = scope.peek(angle.velocity),
						})
					elseif scope.peek(angle.type) == "Infinite" then
						table.insert(assembledData, {
							type = "Infinite",
							color = scope.peek(angle.color),
							velocity = scope.peek(angle.velocity),
						})
					elseif scope.peek(angle.type) == "Wait" then
						table.insert(assembledData, {
							type = "Wait",
							time = scope.peek(angle.time),
						})
					end
				end
				table.insert(assembledRotators, {
					lightName = scope.peek(rotator.lightName),
					data = assembledData,
				})
			end

			if utils.compareTables(currentPattern.pattern.rotators, assembledRotators) == true then
				return
			end

			currentPattern.pattern.rotators = assembledRotators
			props.UnsavedChanges:set(true)
		end
	end

	local function promptReset()
		popup:addPopup(scope, {
			title = "Reset Rotators",
			description = "Are you sure you want to reset all rotators?\n<b>All data will be lost.</b>",
			actions = {
				{
					text = "Cancel",
					type = "primary",
					key = 1,
					callback = function(newPopup)
						popup:removePopup(newPopup)
					end,
					keybind = Enum.KeyCode.Escape,
				},
				{
					text = "Reset",
					type = "danger",
					key = 2,
					callback = function(newPopup)
						popup:removePopup(newPopup)
						playing:set(false)
						rotators:set({})
						updateCurrentConfiguration()
					end,
				},
			},
		})
	end

	scope:Observer(props.CurrentPattern):onChange(function()
		local currentPattern = scope.peek(props.CurrentPattern)
		local currentVehicle = scope.peek(props.CurrentVehicle)
		if currentPattern ~= nil then
			playing:set(false)
			if typeof(currentVehicle) == "Instance" then
				currentConfiguration = chassisHandler:getConfiguration(currentVehicle)
				if currentConfiguration ~= nil then
					colors:set(currentConfiguration.lightSettings.colors)
				else
					colors:set(chassisHandler.defaults.colors)
				end
			end

			local newRotators = {}
			for i, rotator in currentPattern.pattern.rotators do
				local data = {}
				for angleId, angle in rotator.data do
					if angle.type == "Angle" then
						table.insert(data, angleId, {
							type = firstScope:Value(angle.type :: any),
							color = angle.color and firstScope:Value(angle.color) or nil,
							angle = angle.angle and firstScope:Value(angle.angle) or nil,
							velocity = angle.velocity and firstScope:Value(angle.velocity) or nil,
						})
					elseif angle.type == "Infinite" then
						table.insert(data, angleId, {
							type = firstScope:Value(angle.type :: any),
							color = angle.color and firstScope:Value(angle.color) or nil,
							velocity = angle.velocity and firstScope:Value(angle.velocity) or nil,
						})
					elseif angle.type == "Wait" then
						table.insert(data, angleId, {
							type = firstScope:Value(angle.type :: any),
							time = angle.time and firstScope:Value(angle.time) or nil,
						})
					end
				end
				local newRotator = {
					lightName = firstScope:Value(rotator.lightName),
					currentPercentage = firstScope:Value(0),
					currentAngle = firstScope:Value(1),
					currentValue = firstScope:Value(0),
					previousGoal = 0,
					data = firstScope:Value(data),
				}
				table.insert(newRotators, i, newRotator)
			end
			log.debug(newRotators)
			rotators:set(newRotators)
		end
	end)

	local function addRotator(atPoint: number?)
		local unpause = temporarlyPause()
		local currentRotators = scope.peek(rotators)
		if atPoint == nil then
			atPoint = #currentRotators + 1
		end
		table.insert(currentRotators, atPoint :: number, {
			lightName = firstScope:Value("Rotator " .. atPoint :: number),
			data = firstScope:Value({
				{
					type = firstScope:Value("Angle" :: any), -- me when luau types
					color = firstScope:Value(1),
					angle = firstScope:Value(90),
					velocity = firstScope:Value(0.1),
				},
				{
					type = firstScope:Value("Angle" :: any), -- me when luau types
					color = firstScope:Value(1),
					angle = firstScope:Value(-90),
					velocity = firstScope:Value(0.1),
				},
			}),
			currentAngle = firstScope:Value(1),
			currentPercentage = firstScope:Value(0),
			currentValue = firstScope:Value(0),
		})

		rotators:set(currentRotators)
		updateCurrentConfiguration()
		unpause()
	end

	-- player
	local connection: RBXScriptConnection? = nil
	scope:Observer(playing):onChange(function()
		local isPlaying = scope.peek(playing)
		local currentRotators = scope.peek(rotators)
		if isPlaying == true then
			log.debug("Playing")
			for _, data in currentRotators do
				if data.previousGoal == nil then
					data.previousGoal = 0
				end
			end

			connection = RunService.Heartbeat:Connect(function(deltaTime: number)
				for _, data in currentRotators do
					local currentAngles = scope.peek(data.data)
					local angleId = scope.peek(data.currentAngle)
					local currentPercentage = scope.peek(data.currentPercentage)
					if angleId > #currentAngles then
						angleId = 1
						currentPercentage = 0
					end

					data.currentAngle:set(angleId) -- Fusion wont push this change if its the same value
					local currentAngle = currentAngles[angleId]
					if scope.peek(currentAngle.type) == "Angle" then
						local currentRotation = math.rad(scope.peek(data.currentValue))
						local goal = math.rad(scope.peek(currentAngle.angle))
						local velocity: number = math.abs(scope.peek(currentAngle.velocity))

						local difference = goal - currentRotation
						-- log.debug(angleId, currentRotation, math.clamp(difference, -velocity, velocity))
						if math.abs(difference) == 0 then
							data.currentAngle:set(if angleId ~= #currentAngles then angleId + 1 else 1)
							data.previousGoal = goal
							currentPercentage = 0
						else
							currentRotation += math.clamp(difference, -velocity, velocity)
							currentPercentage = 1 - ((goal - currentRotation) / (goal - data.previousGoal :: number))

							data.currentValue:set(math.deg(currentRotation))
						end
					elseif scope.peek(currentAngle.type) == "Infinite" then
						local currentRotation = math.rad(scope.peek(data.currentValue))
						local velocity: number = scope.peek(currentAngle.velocity)
						-- log.debug(angleId, scope.peek(currentAngle.color))

						currentRotation += (velocity * 60) * deltaTime
						data.currentValue:set(math.deg(currentRotation) % 360)
					else
						-- log.debug(angleId, scope.peek(currentAngle.time))
						currentPercentage += deltaTime / scope.peek(currentAngle.time)
						if currentPercentage >= 1 then
							data.currentAngle:set(if angleId ~= #currentAngles then angleId + 1 else 1)
							currentPercentage = 0
						end
					end
					data.currentPercentage:set(currentPercentage)
				end
			end)
		else
			log.debug("Stopping")
			if connection ~= nil then
				connection:Disconnect()
				connection = nil
			end

			-- Reset the faders to ensure they stay in sync
			for _, data in currentRotators do
				data.currentAngle:set(1)
				data.currentPercentage:set(0)
				data.currentValue:set(0)
				data.previousGoal = 0
			end
		end
	end)

	scope:Observer(props.Enabled):onChange(function()
		local enabled = scope.peek(props.Enabled)
		if enabled == false then
			playing:set(false)
		end
	end)

	scope:Observer(props.CurrentPage):onBind(function()
		local currentPage = scope.peek(props.CurrentPage)
		if currentPage ~= "Rotators" then
			playing:set(false)
		end
	end)

	local playHovered = scope:Value(false)
	local size = scope:Value(Vector2.one)
	local sectionsTotalSpace = scope:Value(Vector2.one)
	return scope:base {
		Name = "Rotators",
		AnchorPoint = Vector2.new(0.5, 0),
		Position = scope:Spring(
			scope:Computed(function(use)
				local currentPage = use(props.CurrentPage)
				if currentPage == "Rotators" then
					return UDim2.fromScale(0.5, 0.0462962963)
				end
				return UDim2.fromScale(1.5, 0.0462962963)
			end),
			20,
			0.75
		),
		Size = UDim2.fromScale(1, 0.9537037037),
		BackgroundTransparency = 1,

		[Fusion.OnEvent "InputBegan"] = function(input: InputObject)
			if input.UserInputType == Enum.UserInputType.Keyboard then
				if input.KeyCode == Enum.KeyCode.Space or input.KeyCode == Enum.KeyCode.P then
					playing:set(not scope.peek(playing))
				elseif input.KeyCode == Enum.KeyCode.LeftShift then
					holdingShift:set(true)
				end
			end
		end :: unknown,

		[Fusion.OnEvent "InputEnded"] = function(input: InputObject)
			if input.UserInputType == Enum.UserInputType.Keyboard then
				if input.KeyCode == Enum.KeyCode.LeftShift then
					holdingShift:set(false)
				end
			end
		end :: unknown,

		[Fusion.Children] = {
			scope:base {
				Name = "Header",
				AnchorPoint = Vector2.new(0, 0),
				Position = UDim2.fromScale(0, 0),
				Size = UDim2.fromScale(1, 0.0582524272),
				BackgroundColor3 = currentTheme.colors.mantle,

				[Fusion.Children] = {
					scope:base {
						ClassName = "ScrollingFrame",
						AnchorPoint = Vector2.new(0.5, 0.5),
						Position = UDim2.fromScale(0.5, 0.5),
						Size = UDim2.fromScale(1, 1),
						BackgroundTransparency = 1,
						CanvasSize = UDim2.new(),
						ScrollBarThickness = 3,
						ScrollBarImageColor3 = currentTheme.colors.text,
						TopImage = "rbxasset://textures/ui/Scroll/scroll-middle.png",
						BottomImage = "rbxasset://textures/ui/Scroll/scroll-middle.png",
						AutomaticCanvasSize = Enum.AutomaticSize.X,
						ClipsDescendants = false,

						[Fusion.Children] = Fusion.Child {
							scope:New("UIAspectRatioConstraint") {
								AspectRatio = 32,
							},

							scope:New "UIListLayout" {
								Padding = UDim.new(0.0078125, 0),
								FillDirection = Enum.FillDirection.Horizontal,
								HorizontalAlignment = Enum.HorizontalAlignment.Center,
								VerticalAlignment = Enum.VerticalAlignment.Center,
								SortOrder = Enum.SortOrder.LayoutOrder,
							},

							scope:iconButton {
								Size = UDim2.fromScale(0.0260416667, 0.8333333333),
								CornerRadius = UDim.new(0.2, 0),
								Border = 2,
								Reactive = true,
								LayoutOrder = 100,
								Image = scope:Computed(function(use)
									local isPlaying = use(playing)
									return if isPlaying
										then assets.images.redonUI.pause
										else if use(playHovered)
											then assets.images.redonUI.playFilled
											else assets.images.redonUI.play
								end),
								BackgroundColor3 = currentTheme.colors.mantle,
								ImageColor3 = currentTheme.colors.text,
								MouseEnter = function()
									playHovered:set(true)
								end,
								MouseLeave = function()
									playHovered:set(false)
								end,
								[Fusion.OnEvent "Activated"] = function()
									playing:set(not scope.peek(playing))
								end,
							},

							scope:iconButton {
								Size = UDim2.fromScale(0.0260416667, 0.8333333333),
								CornerRadius = UDim.new(0.2, 0),
								Border = 2,
								Reactive = true,
								LayoutOrder = 102,
								Image = assets.images.redonUI.refresh,
								BackgroundColor3 = currentTheme.colors.mantle,
								ImageColor3 = currentTheme.colors.text,
								[Fusion.OnEvent "Activated"] = function()
									promptReset()
								end,
							},
						},
					},
				},
			},

			scope:base {
				Size = UDim2.fromScale(1, 1),
				AnchorPoint = Vector2.new(0.5, 1),
				Position = UDim2.fromScale(0.5, 1),
				BackgroundTransparency = 1,
				ClipsDescendants = true,

				[Fusion.Children] = {
					scope:New("UIAspectRatioConstraint") {
						AspectRatio = 1.9793814433,
					},

					scope:base {
						ClassName = "ScrollingFrame",
						Name = "Content",
						Size = UDim2.fromScale(0.9739583333, 0.9174757282), -- 1870, 945
						AnchorPoint = Vector2.new(0.5, 1),
						Position = UDim2.fromScale(0.5, 1),
						BackgroundTransparency = 1,
						CanvasSize = UDim2.new(),
						AutomaticCanvasSize = Enum.AutomaticSize.X,
						ScrollBarThickness = 3,
						ScrollBarImageColor3 = currentTheme.colors.text,
						TopImage = "rbxasset://textures/ui/Scroll/scroll-middle.png",
						BottomImage = "rbxasset://textures/ui/Scroll/scroll-middle.png",
						[Fusion.Out "AbsoluteSize"] = size :: unknown,
						ClipsDescendants = false,

						[Fusion.Children] = Fusion.Child {
							scope:New("UIListLayout") {
								Padding = UDim.new(0.0130208333, 0),
								FillDirection = Enum.FillDirection.Horizontal,
								HorizontalAlignment = scope:Computed(function(use)
									return if use(sectionsTotalSpace).X > use(size).X
										then Enum.HorizontalAlignment.Left
										else Enum.HorizontalAlignment.Center
								end),
								VerticalAlignment = Enum.VerticalAlignment.Top,
								SortOrder = Enum.SortOrder.LayoutOrder,
								[Fusion.Out "AbsoluteContentSize"] = sectionsTotalSpace :: unknown,
							},

							scope:ForPairs(rotators, function(_, scope: typeof(scope), key: number, rotator)
								return key,
									scope:rotator {
										key = key,
										rotator = rotator,
										playing = playing,
										holdingShift = holdingShift,
										colors = colors,
										rotators = rotators,
										temporarlyPause = temporarlyPause,
										updateCurrentConfiguration = updateCurrentConfiguration,
										addRotator = addRotator,
										firstScope = firstScope,
										size = size,
									}
							end),
						},
					},

					scope:textButton {
						Size = UDim2.fromScale(0.1822916667, 0.0776699029),
						AnchorPoint = Vector2.new(0.5, 0.5),
						Position = UDim2.fromScale(0.5, 0.5),
						BackgroundColor3 = Color3.new(1, 1, 1),
						Gradient = ColorSequence.new(currentTheme.colors.sky, currentTheme.colors.sapphire),
						CornerRadius = UDim.new(0.2, 0),
						Text = "Add Section",
						TextScaled = true,
						MaxTextSize = 40,
						TextColor3 = currentTheme.colors.mantle,
						Border = 2,
						Reactive = true,
						ButtonGlow = true,
						ButtonGlowColor3 = if currentTheme.colors.white == Color3.new(1, 1, 1)
							then currentTheme.colors.text
							else currentTheme.colors.base,
						Shadow = true,
						ShadowColor3 = currentTheme.colors.sky,
						Visible = scope:Computed(function(use)
							return #use(rotators) == 0
						end),

						[Fusion.OnEvent "Activated"] = function()
							addRotator()
						end,
					},
				},
			},
		},
	}
end


--#selene: allow(shadowing)
-- Redon Tech Emergency Vehicle Creator, MIT License
local root = script.Parent.Parent.Parent.Parent.Parent.Parent

local Fusion = require(root.Packages.fusion)
local RedonUI = require(root.Packages["redon-ui"])
local types = require(root.Plugin.types)
local popup = require(root.Plugin.Components.popup)
local chassisHandler = require(root.Plugin.chassisHandler)
local assets = require(root.Plugin.assets)
local log = require(root.Plugin.log)
local settings = require(root.Plugin.settings)
local utils = require(root.Plugin.utils)

local angle = require(script.Parent.angle)
local components = {
	angle = angle,
}

--[[
	Rotators
	Creates the rotators screen for the main app
]]
return function(
	baseScope: types.Scope,
	props: {
		key: number,
		rotator: types.rotatorSectionState,
		playing: Fusion.Value<boolean>,
		holdingShift: Fusion.Value<boolean>,
		colors: Fusion.Value<{ chassisHandler.color }>,
		rotators: Fusion.Value<{ types.rotatorSectionState }>,
		temporarlyPause: () -> () -> (),
		updateCurrentConfiguration: () -> (),
		addRotator: (number) -> (),
		firstScope: types.Scope,
		size: Fusion.Value<Vector2>,
	}
): Fusion.Child
	local currentTheme = RedonUI.theme.theme:now()
	local scope = baseScope:innerScope(components)

	local dataSize = scope:Value(Vector2.one)
	local color = scope:Computed(function(use)
		if use(props.playing) == false then
			return Color3.new()
		end

		local currentAngles = use(props.rotator.data)
		local currentAngle = currentAngles[use(props.rotator.currentAngle)]
		if currentAngle == nil then
			log.warn("Somehow the current angle is nil", currentAngle, scope.peek(props.rotator.currentAngle))
			return Color3.new()
		end
		local colorId = use(currentAngle.color)
		if colorId == nil then
			return Color3.new()
		end
		local colorData = scope.peek(props.colors)[colorId]
		local finalColor = if colorData == nil
			then Color3.new()
			else if utils.bloomColors[colorData.name] ~= nil
				then utils.bloomColors[colorData.name]
				else colorData.lightoColor
		return finalColor
	end)
	return scope:base {
		Name = props.key,
		Size = UDim2.fromScale(0.1764705882, 0.9735449735),
		BackgroundColor3 = currentTheme.colors.mantle,
		CornerRadius = scope:Computed(function(use)
			return UDim.new(0, 0.0171428571 * use(props.size).Y) -- Once again, I shouldn't need to do this
		end),
		LayoutOrder = props.key,

		[Fusion.Children] = {
			scope:base {
				Size = UDim2.fromScale(1, 0.3260869565),
				CornerRadius = UDim.new(0.05, 0),
				BackgroundColor3 = currentTheme.colors.crust,

				[Fusion.Children] = {
					scope:New("ImageLabel") {
						Name = "Light",
						Size = UDim2.fromScale(1, 1),
						AnchorPoint = Vector2.new(0.5, 0.5),
						Position = UDim2.fromScale(0.5, 0.5),
						Rotation = props.rotator.currentValue,
						BackgroundTransparency = 1,
						Image = assets.images.elsCreator.light,
						ImageColor3 = currentTheme.colors.text,
						ScaleType = Enum.ScaleType.Fit,
						ZIndex = 3,
					},

					scope:base {
						Size = UDim2.fromScale(1, 1),
						Position = UDim2.fromScale(0.5, 0.5),
						AnchorPoint = Vector2.new(0.5, 0.5),
						Rotation = props.rotator.currentValue,
						BackgroundTransparency = 1,
						Visible = scope:Computed(function(use)
							return use(props.playing) == true and use(color) ~= Color3.new()
						end),

						[Fusion.Children] = Fusion.Child {
							scope:New("ImageLabel") {
								Name = "Beam",
								Size = UDim2.fromScale(1, 1),
								AnchorPoint = Vector2.new(0.5, 0.5),
								Position = UDim2.fromScale(0.5, 0.5),
								BackgroundTransparency = 1,
								Image = assets.images.elsCreator.beam,
								ImageColor3 = scope:Computed(function(use)
									return if use(settings.values.fakeBloom) == false
										then use(color)
										else Color3.new(1, 1, 1)
								end),
								ScaleType = Enum.ScaleType.Fit,
								ZIndex = 2,

								[Fusion.Children] = {
									scope:New("UIGradient") {
										Offset = Vector2.new(0, 0.6),
										Rotation = 90,
										Transparency = NumberSequence.new({
											NumberSequenceKeypoint.new(0, 0),
											NumberSequenceKeypoint.new(0.4, 1),
											NumberSequenceKeypoint.new(1, 1),
										}),
									},
								},
							},

							scope:New("ImageLabel") {
								Name = "LightColor",
								Size = UDim2.fromScale(1, 1),
								AnchorPoint = Vector2.new(0.5, 0.5),
								Position = UDim2.fromScale(0.5, 0.5),
								BackgroundTransparency = 1,
								Image = assets.images.elsCreator.lightColor,
								ImageColor3 = scope:Computed(function(use)
									return if use(settings.values.fakeBloom) == false
										then use(color)
										else Color3.new(1, 1, 1)
								end),
								ScaleType = Enum.ScaleType.Fit,
								ZIndex = 2,
							},

							scope:Computed(function(use, scope: typeof(scope))
								return if use(settings.values.fakeBloom) == true
									then {
										scope:New("ImageLabel") {
											Name = "Bloom1",
											Size = UDim2.fromScale(1.2, 1.2),
											AnchorPoint = Vector2.new(0.5, 0.5),
											Position = UDim2.fromScale(0.5, 0.5),
											BackgroundTransparency = 1,
											Image = assets.images.elsCreator.bloom1,
											ImageColor3 = color,
											ScaleType = Enum.ScaleType.Fit,
										},

										scope:New("ImageLabel") {
											Name = "Bloom2",
											Size = UDim2.fromScale(2, 2),
											AnchorPoint = Vector2.new(0.5, 0.5),
											Position = UDim2.fromScale(0.5, 0.5),
											BackgroundTransparency = 1,
											Image = assets.images.elsCreator.bloom2,
											ImageColor3 = color,
											ScaleType = Enum.ScaleType.Fit,
										},

										scope:New("ImageLabel") {
											Name = "Bloom3",
											Size = UDim2.fromScale(1, 1),
											AnchorPoint = Vector2.new(0.5, 0.5),
											Position = UDim2.fromScale(0.5, 0.5),
											BackgroundTransparency = 1,
											Image = assets.images.elsCreator.bloom3,
											ImageColor3 = color,
											ScaleType = Enum.ScaleType.Fit,
										},
									}
									else {}
							end),
						},
					},
				},
			},

			scope:base {
				Name = "Header",
				Size = UDim2.fromScale(0.8484848485, 0.0574712644),
				Position = UDim2.fromScale(0.5, 0.3532608696),
				AnchorPoint = Vector2.new(0.5, 0),
				BackgroundTransparency = 1,

				[Fusion.Children] = {
					scope:New("UIListLayout") {
						Padding = UDim.new(0.0535714286, 0),
						FillDirection = Enum.FillDirection.Horizontal,
						HorizontalAlignment = Enum.HorizontalAlignment.Center,
						VerticalAlignment = Enum.VerticalAlignment.Center,
						SortOrder = Enum.SortOrder.LayoutOrder,
					},

					scope:iconButton {
						Size = UDim2.fromScale(0.1785714286, 1),
						LayoutOrder = 1,
						CornerRadius = UDim.new(0.2, 0),
						Border = 2,
						Reactive = true,
						Image = assets.images.redonUI.remove,
						BackgroundColor3 = currentTheme.colors.crust,
						ImageColor3 = currentTheme.colors.text,

						[Fusion.OnEvent "Activated"] = function()
							local function remove()
								local unpause = props.temporarlyPause()
								local currentRotators = scope.peek(props.rotators)
								table.remove(currentRotators, props.key)
								props.rotators:set(currentRotators)
								props.updateCurrentConfiguration()
								unpause()
							end

							if props.holdingShift then
								remove()
								return
							end

							popup:addPopup(scope, {
								title = "Remove Rotator",
								description = `Are you sure you want to delete rotator <b>{props.key}</b>?\n<b>All data will be lost.</b>`,
								actions = {
									{
										text = "Cancel",
										type = "primary",
										key = 1,
										callback = function(newPopup)
											popup:removePopup(newPopup)
										end,
										keybind = Enum.KeyCode.Escape,
									},
									{
										text = "Delete",
										type = "danger",
										key = 2,
										callback = function(newPopup)
											popup:removePopup(newPopup)
											remove()
										end,
										keybind = Enum.KeyCode.Return,
									},
								},
							})
						end,
					},

					scope:textBox {
						Size = UDim2.fromScale(0.5357142857, 1),
						LayoutOrder = 2,
						CornerRadius = UDim.new(0.2, 0),
						Border = 1,
						BackgroundColor3 = currentTheme.colors.crust,
						Text = props.rotator.lightName,
						[Fusion.Out "Text"] = props.rotator.lightName :: unknown,
						[Fusion.OnEvent "FocusLost"] = function()
							props.updateCurrentConfiguration()
						end,
					},

					scope:iconButton {
						Size = UDim2.fromScale(0.1785714286, 1),
						LayoutOrder = 3,
						CornerRadius = UDim.new(0.2, 0),
						Border = 2,
						Reactive = true,
						Image = assets.images.redonUI.add,
						BackgroundColor3 = currentTheme.colors.crust,
						ImageColor3 = currentTheme.colors.text,

						[Fusion.OnEvent "Activated"] = function()
							props.addRotator(props.key + 1)
						end,
					},
				},
			},

			scope:base {
				ClassName = "ScrollingFrame",
				Name = "Data",
				Size = UDim2.fromScale(0.8484848485, 0.5380434783), -- 150, 495
				Position = UDim2.fromScale(0.5, 0.972826087),
				AnchorPoint = Vector2.new(0.5, 1),
				BackgroundTransparency = 1,
				CanvasSize = UDim2.new(),
				ScrollBarThickness = 3,
				ScrollBarImageColor3 = currentTheme.colors.text,
				TopImage = "rbxasset://textures/ui/Scroll/scroll-middle.png",
				BottomImage = "rbxasset://textures/ui/Scroll/scroll-middle.png",
				AutomaticCanvasSize = Enum.AutomaticSize.Y,
				[Fusion.Out "AbsoluteSize"] = dataSize :: unknown,

				[Fusion.Children] = Fusion.Child {
					scope:New("UIListLayout") {
						Padding = UDim.new(0.0202020202, 0),
						FillDirection = Enum.FillDirection.Vertical,
						HorizontalAlignment = Enum.HorizontalAlignment.Center,
						VerticalAlignment = Enum.VerticalAlignment.Top,
						SortOrder = Enum.SortOrder.LayoutOrder,
					},

					scope:New("UIPadding") {
						PaddingTop = UDim.new(0, 1),
						PaddingBottom = UDim.new(0, 15),
					},

					scope:ForPairs(props.rotator.data, function(_, scope: typeof(scope), key: number, angle)
						return key,
							scope:angle {
								key = key,
								angle = angle,
								rotator = props.rotator,
								playing = props.playing,
								colors = props.colors,
								updateCurrentConfiguration = props.updateCurrentConfiguration,
								firstScope = props.firstScope,
								dataSize = dataSize,
							}
					end),

					scope:base {
						Size = UDim2.fromScale(0.5357142857, 0.1010101010),
						BackgroundTransparency = 1,
						LayoutOrder = 4000,

						[Fusion.Children] = {
							scope:iconButton {
								Size = UDim2.fromScale(0.3333333333, 1),
								LayoutOrder = 1,
								CornerRadius = UDim.new(0.2, 0),
								Border = 1,
								Reactive = true,
								Image = assets.images.redonUI.remove,
								BackgroundColor3 = currentTheme.colors.crust,
								ImageColor3 = currentTheme.colors.text,

								[Fusion.OnEvent "Activated"] = function()
									if #scope.peek(props.rotator.data) == 1 then
										log.warn("Cannot remove the last angle")
										return
									end
									local deleting = #scope.peek(props.rotator.data)

									local function remove()
										local currentData = scope.peek(props.rotator.data)
										table.remove(currentData, deleting)
										props.rotator.data:set(currentData)
									end

									if props.holdingShift then
										remove()
										return
									end

									popup:addPopup(scope, {
										title = "Remove Rotator",
										description = `Are you sure you want to delete rotator <b>{deleting}</b>?\n<b>All data will be lost.</b>`,
										actions = {
											{
												text = "Cancel",
												type = "primary",
												key = 1,
												callback = function(newPopup)
													popup:removePopup(newPopup)
												end,
												keybind = Enum.KeyCode.Escape,
											},
											{
												text = "Delete",
												type = "danger",
												key = 2,
												callback = function(newPopup)
													popup:removePopup(newPopup)
													remove()
												end,
												keybind = Enum.KeyCode.Return,
											},
										},
									})
								end,
							},

							scope:iconButton {
								Size = UDim2.fromScale(0.3333333333, 1),
								Position = UDim2.fromScale(1, 0),
								AnchorPoint = Vector2.new(1, 0),
								LayoutOrder = 2,
								CornerRadius = UDim.new(0.2, 0),
								Border = 1,
								Reactive = true,
								Image = assets.images.redonUI.add,
								BackgroundColor3 = currentTheme.colors.crust,
								ImageColor3 = currentTheme.colors.text,

								[Fusion.OnEvent "Activated"] = function()
									local currentData = scope.peek(props.rotator.data)
									table.insert(currentData, {
										type = props.firstScope:Value("Wait" :: any), -- the day I dont need this I will be so glad
										time = props.firstScope:Value(0.5),
									})
									props.rotator.data:set(currentData)
								end,
							},
						},
					},
				},
			},
		},
	}
end


-- Redon Tech Emergency Vehicle Creator, MIT License
local root = script.Parent.Parent.Parent

local Fusion = require(root.Packages.fusion)
local RedonUI = require(root.Packages["redon-ui"])
local types = require(root.Plugin.types)
local chassisHandler = require(root.Plugin.chassisHandler)
local log = require(root.Plugin.log)

local widget = require(script.Parent.base.widget)
local topbar = require(script.topbar)
local components = {
	widget = widget,
	topbar = topbar,
}

local functions = require(script.setup.functions)
local sirens = require(script.setup.sirens)
local lightSettings = require(script.setup.lightSettings)
local flashers = require(script.els.flashers)
local faders = require(script.els.faders)
local rotators = require(script.els.rotators)

type props = {
	Name: string,
	Version: string,

	Enabled: Fusion.UsedAs<boolean>,
	Mode: Fusion.Value<types.mode>,
	CurrentVehicle: Fusion.Value<Model | string?>,
	PossibleVehicle: Fusion.Value<Model?>,

	ReturnTo: Fusion.Value<types.returnTo>,
	PopupShown: Fusion.Value<boolean>,
}

--[[
	Main
	Creates the main app for the plugin
]]
return function(baseScope: types.Scope, props: props): Fusion.Child
	local scope = Fusion.innerScope(baseScope, components)
	local currentTheme = RedonUI.theme.theme:now()

	local currentPanel = scope:Value("Vehicle Setup")
	local currentPage = scope:Value(nil)
	local unsavedChanges = scope:Value(false)
	local currentPattern = scope:Value(nil)
	local installPluginOrUpgrade: Fusion.Value<boolean?> = scope:Value(nil)

	scope:Observer(props.PossibleVehicle):onChange(function()
		local currentPossibleVehicle = scope.peek(props.PossibleVehicle)
		if currentPossibleVehicle ~= nil then
			local currentConfiguration = chassisHandler:getConfiguration(currentPossibleVehicle)
			if currentConfiguration ~= nil then
				log.debug("Found vehicle configuration for possible vehicle")
				props.CurrentVehicle:set(currentPossibleVehicle)
				props.PossibleVehicle:set(nil)
				currentPanel:set("Vehicle Setup")
				currentPage:set("Functions")
			else
				local hasOldPlugin = chassisHandler:hasEVCChassisPluginInstalled(currentPossibleVehicle)
				if hasOldPlugin then
					installPluginOrUpgrade:set(true)
				else
					installPluginOrUpgrade:set(false)
				end
				currentPanel:set("Vehicle Setup")
				currentPage:set("Functions")
			end
		end
	end)

	local AbsoluteSize = scope:Value(Vector2.one)
	return scope:widget {
		pluginGuiId = `{props.Name}_Main`,
		InitialDockState = Enum.InitialDockState.Float,
		InitialEnabled = false,
		FloatingYSize = 648,
		FloatingXSize = 1152,
		InitialEnabledShouldOverrideRestore = true,
		[Fusion.Out "AbsoluteSize"] = AbsoluteSize,

		Title = scope:Computed(function(use)
			return `EVC {use(currentPanel)} ({use(props.Version)}) {if use(unsavedChanges)
				then "Unsaved Changes*"
				else ""}`
		end),

		Enabled = scope:Computed(function(use)
			local enable = use(props.Enabled) == true and use(props.Mode) == "main"
			if enable and scope.peek(props.CurrentVehicle) ~= nil then
				currentPanel:set("Vehicle Setup")
				currentPage:set("Functions")
			elseif enable and scope.peek(props.PossibleVehicle) == nil then
				currentPattern:set({
					functionId = 0,
					patternId = 0,
					pattern = {
						flashers = {},
						faders = {},
						rotators = {},
					},
				})
				currentPanel:set("ELS Setup")
				currentPage:set("Flashers")
			end
			return enable
		end),

		[Fusion.Children] = {
			scope:base {
				Name = "Main",
				AnchorPoint = Vector2.new(0.5, 0.5),
				Position = UDim2.fromScale(0.5, 0.5),
				Size = UDim2.fromScale(1, 1),
				BackgroundColor3 = currentTheme.colors.base,
				Interactable = scope:Computed(function(use)
					return not use(props.PopupShown)
				end),

				[Fusion.Children] = Fusion.Child {
					scope:topbar {
						UnsavedChanges = unsavedChanges,
						CurrentPanel = currentPanel :: any,
						CurrentPage = currentPage,
						CurrentVehicle = props.CurrentVehicle,
						PossibleVehicle = props.PossibleVehicle,
						ReturnTo = props.ReturnTo,
						Mode = props.Mode,
						CurrentPattern = currentPattern,
					},

					functions(scope, {
						UnsavedChanges = unsavedChanges,
						CurrentPanel = currentPanel :: any,
						CurrentPage = currentPage,
						Mode = props.Mode,
						CurrentVehicle = props.CurrentVehicle,
						CurrentPattern = currentPattern,
						ReturnTo = props.ReturnTo,
					}),

					sirens(scope, {
						UnsavedChanges = unsavedChanges,
						CurrentPanel = currentPanel :: any,
						CurrentPage = currentPage,
						Mode = props.Mode,
						CurrentVehicle = props.CurrentVehicle,
					}),

					lightSettings(scope, {
						UnsavedChanges = unsavedChanges,
						CurrentPanel = currentPanel :: any,
						CurrentPage = currentPage,
						Mode = props.Mode,
						CurrentVehicle = props.CurrentVehicle,
					}),

					flashers(scope, {
						UnsavedChanges = unsavedChanges,
						CurrentPanel = currentPanel :: any,
						CurrentPage = currentPage,
						Mode = props.Mode,
						CurrentVehicle = props.CurrentVehicle,
						CurrentPattern = currentPattern,
						Enabled = props.Enabled,
					}),

					faders(scope, {
						UnsavedChanges = unsavedChanges,
						CurrentPanel = currentPanel :: any,
						CurrentPage = currentPage,
						Mode = props.Mode,
						CurrentVehicle = props.CurrentVehicle,
						CurrentPattern = currentPattern,
						Enabled = props.Enabled,
					}),

					rotators(scope, {
						UnsavedChanges = unsavedChanges,
						CurrentPanel = currentPanel :: any,
						CurrentPage = currentPage,
						Mode = props.Mode,
						CurrentVehicle = props.CurrentVehicle,
						CurrentPattern = currentPattern,
						Enabled = props.Enabled,
					}),

					scope:base {
						Size = UDim2.fromScale(2, 2),
						AnchorPoint = Vector2.new(0.5, 0.5),
						BackgroundColor3 = currentTheme.colors.crust,
						BackgroundTransparency = scope:Spring(
							scope:Computed(function(use)
								return if use(installPluginOrUpgrade) == nil then 1 else 0.5
							end),
							20,
							1
						),
						Position = scope:Spring(
							scope:Computed(function(use)
								return if use(installPluginOrUpgrade) == nil
									then UDim2.fromScale(0.5, 1.5)
									else UDim2.fromScale(0.5, 0.5)
							end),
							20,
							0.6
						),
						ZIndex = 4000,

						[Fusion.Children] = {
							scope:New("UIListLayout") {
								HorizontalAlignment = Enum.HorizontalAlignment.Center,
								VerticalAlignment = Enum.VerticalAlignment.Center,
							},

							scope:base {
								AutomaticSize = Enum.AutomaticSize.XY,
								BackgroundColor3 = currentTheme.colors.base,
								Border = 2,
								CornerRadius = UDim.new(0, 15),
								Visible = scope:Computed(function(use)
									return use(installPluginOrUpgrade) ~= nil
								end),

								[Fusion.Children] = {
									scope:New("UIPadding") {
										PaddingTop = UDim.new(0, 10),
										PaddingBottom = UDim.new(0, 10),
										PaddingLeft = UDim.new(0, 10),
										PaddingRight = UDim.new(0, 10),
									},

									scope:New("UIListLayout") {
										Padding = UDim.new(0, 15),
										FillDirection = Enum.FillDirection.Vertical,
										HorizontalAlignment = Enum.HorizontalAlignment.Center,
										VerticalAlignment = Enum.VerticalAlignment.Top,
										SortOrder = Enum.SortOrder.LayoutOrder,
									},

									scope:textLabel {
										Size = UDim2.fromOffset(300, 50),
										AnchorPoint = Vector2.new(0.5, 0),
										Position = UDim2.fromScale(0.5, 0),
										Text = "Install Emergency Vehicle Handler",
										TextScaled = true,
										MaxTextSize = 30,
										FontWeight = Enum.FontWeight.Bold,
										LayoutOrder = 1,
									},

									scope:textLabel {
										Size = UDim2.fromOffset(400, 50),
										AnchorPoint = Vector2.new(0, 0),
										Position = UDim2.new(0, 0, 0, 65),
										Text = scope:Computed(function(use)
											if use(installPluginOrUpgrade) == true then
												return "Would you like to automatically update your EVC Chassis Plugin to Emergency Vehicle Handler?\n\n<b>Backup your vehicle before upgrading, data loss may occur.</b>"
											end

											return "Would you like to install Emergency Vehicle Handler?"
										end),
										RichText = true,
										TextScaled = true,
										TextSize = 20,
										FontWeight = Enum.FontWeight.Regular,
										MaxTextSize = 20,
										TextWrapped = true,
										TextYAlignment = Enum.TextYAlignment.Top,
										AutomaticSize = Enum.AutomaticSize.Y,
										LayoutOrder = 2,
									},

									scope:base {
										Size = UDim2.fromOffset(300, 50),
										AnchorPoint = Vector2.new(0.5, 1),
										Position = UDim2.fromScale(0.5, 1),
										BackgroundTransparency = 1,
										LayoutOrder = 3,

										[Fusion.Children] = Fusion.Child {
											scope:New("UIListLayout") {
												Padding = UDim.new(0, 15),
												FillDirection = Enum.FillDirection.Horizontal,
												HorizontalAlignment = Enum.HorizontalAlignment.Center,
												VerticalAlignment = Enum.VerticalAlignment.Center,
												SortOrder = Enum.SortOrder.LayoutOrder,
											},

											scope:textButton {
												Size = UDim2.fromOffset(175, 35),
												Text = "Cancel",
												TextScaled = true,
												MaxTextSize = 25,
												TextColor3 = currentTheme.colors.crust,
												BackgroundColor3 = currentTheme.colors.red,
												ButtonGlowColor3 = currentTheme.colors.maroon,
												ShadowColor3 = currentTheme.colors.red,
												ButtonGlow = true,
												Shadow = true,
												Border = 2,
												CornerRadius = UDim.new(0, 10),
												[Fusion.OnEvent "Activated"] = function()
													props.PossibleVehicle:set(nil)
													installPluginOrUpgrade:set(nil)
													props.Mode:set("main")
												end :: unknown,
												LayoutOrder = 1,

												Reactive = true,
											},

											scope:textButton {
												Size = UDim2.fromOffset(175, 35),
												Text = scope:Computed(function(use)
													if use(installPluginOrUpgrade) == true then
														return "Upgrade"
													end

													return "Install"
												end),
												TextScaled = true,
												MaxTextSize = 25,
												TextColor3 = currentTheme.colors.crust,
												BackgroundColor3 = currentTheme.colors.sky,
												ButtonGlowColor3 = currentTheme.colors.text,
												ShadowColor3 = currentTheme.colors.sky,
												ButtonGlow = true,
												Shadow = true,
												Border = 2,
												CornerRadius = UDim.new(0, 10),
												[Fusion.OnEvent "Activated"] = function()
													local currentPossibleVehicle = scope.peek(props.PossibleVehicle)
													if currentPossibleVehicle ~= nil then
														local installed =
															chassisHandler:installPlugin(currentPossibleVehicle)
														if installed then
															props.CurrentVehicle:set(currentPossibleVehicle)
															props.PossibleVehicle:set(nil)
															installPluginOrUpgrade:set(nil)
														else
															log.warn("Failed to install plugin")
															props.PossibleVehicle:set(nil)
															installPluginOrUpgrade:set(nil)
															props.Mode:set("main")
														end
													end
												end :: unknown,
												LayoutOrder = 1,

												Reactive = true,
											},
										},
									},
								},
							},
						},
					},
				},
			},

			scope:textLabel {
				Name = "Version",
				AnchorPoint = Vector2.new(0, 1),
				Position = UDim2.new(0, 5, 1, -5),
				Size = UDim2.fromOffset(240, 12),
				BackgroundTransparency = 1,

				Text = props.Version,
				TextSize = 9,
				FontWeight = Enum.FontWeight.Regular,
				TextXAlignment = Enum.TextXAlignment.Left,
				TextYAlignment = Enum.TextYAlignment.Bottom,
				TextTransparency = 0.5,
			},

			props[Fusion.Children],
		},
	}
end


--#selene: allow(shadowing)
-- Redon Tech Emergency Vehicle Creator, MIT License
local root = script.Parent.Parent.Parent.Parent
local plugin = root:FindFirstAncestorWhichIsA("Plugin")

local Fusion = require(root.Packages.fusion)
local RedonUI = require(root.Packages["redon-ui"])
local types = require(root.Plugin.types)
local log = require(root.Plugin.log)
local LuaEncode = require(root.Packages.LuaEncode)
local Selection = game:GetService("Selection")
local popup = require(root.Plugin.Components.popup)
local utils = require(root.Plugin.utils)
local assets = require(root.Plugin.assets)
local chassisHandler = require(root.Plugin.chassisHandler)

local function testSaveName(name: string, saves: { string }, currentDepth: number): string
	local actualName = if currentDepth == 0 then name else `{name} ({currentDepth})`
	local index = table.find(saves, actualName)
	if index ~= nil then
		return testSaveName(name, saves, currentDepth + 1)
	end
	return actualName
end

type v2Save = {
	faders: {
		{
			Name: string,
			Tweens: {
				{
					EasingDirection: Enum.EasingDirection,
					DelayTime: number,
					RepeatCount: number,
					EasingStyle: Enum.EasingStyle,
					Time: number,
					TransparencyGoal: number,
					Color: number,
					Reverses: boolean,
				}
			},
		}
	},
	rotators: { { Name: string, Angles: { { Angle: number, Color: number, Velocity: number } } } },
	elsCreator: { { WaitTime: number, Columns: { { Name: string, Rows: { number } } } } },
}

type props = {
	CurrentPattern: Fusion.Value<types.selectedPattern?>,
	CurrentVehicle: Fusion.Value<Model | string?>,
}

--[[
	savePopup
	Creates the save menu for the popup created by hitting save/load
]]
return function(scope: types.Scope, props: props): Instance
	local currentTheme = RedonUI.theme.theme:now()

	local initialSettings: { [string]: types.pattern } = {}
	local getSuccess, getData = pcall(function()
		return plugin:GetSetting("RT_EVC_Saves")
	end)
	if getSuccess == true and getData ~= nil then
		initialSettings = getData
	else
		log.warn("Failed to get setting, using default")
	end

	local getV2Success, getV2Data: { [string]: v2Save }? = pcall(function()
		return plugin:GetSetting("savesV2")
	end)
	if getV2Success == true and getV2Data ~= nil then
		plugin:SetSetting("RT_EVC_OLDV2Saves", getV2Data)
		local saveNames: { string } = {}
		for saveName, _ in initialSettings do
			table.insert(saveNames, saveName)
		end

		for saveName, data in getV2Data do
			saveName = testSaveName(saveName, saveNames, 0)
			local newPattern: types.pattern = {
				flashers = {},
				faders = {},
				rotators = {},
			}

			for _, fader in data.faders do
				if fader.Name == nil or fader.Tweens == nil then
					continue
				end
				local newFader: types.faderSection = {
					lightName = fader.Name,
					data = {},
				}
				for _, tween in fader.Tweens do
					if
						tween.EasingDirection == nil
						or tween.DelayTime == nil
						or tween.RepeatCount == nil
						or tween.EasingStyle == nil
						or tween.Time == nil
						or tween.TransparencyGoal == nil
						or tween.Color == nil
						or tween.Reverses == nil
					then
						continue
					end
					local newTween: types.faderData = {
						type = "Advanced",
						time = tween.Time,
						goal = tween.TransparencyGoal,
						color = tween.Color,
						easingStyle = tween.EasingStyle,
						easingDirection = tween.EasingDirection,
					}
					table.insert(newFader.data, newTween)
				end
				if #newFader.data == 0 then
					continue
				end
				table.insert(newPattern.faders, newFader)
			end

			for _, rotator in data.rotators do
				if rotator.Name == nil or rotator.Angles == nil then
					continue
				end
				local newRotator: types.rotatorSection = {
					lightName = rotator.Name,
					data = {},
				}
				for _, angle in rotator.Angles do
					if angle.Angle == nil or angle.Color == nil or angle.Velocity == nil then
						continue
					end
					local newAngle: types.rotatorData = {
						type = "Angle",
						color = angle.Color,
						velocity = angle.Velocity,
						angle = angle.Angle,
					}
					table.insert(newRotator.data, newAngle)
				end
				if #newRotator.data == 0 then
					continue
				end
				table.insert(newPattern.rotators, newRotator)
			end

			for _, els in data.elsCreator do
				if els.Columns == nil or els.WaitTime == nil then
					continue
				end
				local newEls: types.flasherSection = {
					waitTime = els.WaitTime,
					columns = {},
					rowCount = 0,
				}
				for _, column in els.Columns do
					local newColumn = {
						lightName = column.Name,
						rows = column.Rows,
					}
					table.insert(newEls.columns, newColumn)
					newEls.rowCount = math.max(newEls.rowCount, #column.Rows)
				end
				table.insert(newPattern.flashers, newEls)
			end

			initialSettings[saveName] = newPattern
		end
		plugin:SetSetting("RT_EVC_Saves", initialSettings)
		plugin:SetSetting("savesV2", nil)
		log.warn("Converted saves to new format")
	end

	local currentConfiguration = nil
	scope:Observer(props.CurrentVehicle):onChange(function()
		local currentVehicle = scope.peek(props.CurrentVehicle)
		if typeof(currentVehicle) == "Instance" then
			currentConfiguration = chassisHandler:getConfiguration(currentVehicle)
		end
	end)

	local saves: Fusion.Value<{ [string]: types.pattern }> = scope:Value(initialSettings)
	local sortedSaves: Fusion.Value<{ string }> = scope:Value({})
	local initialSortedSaves = {}
	for saveName, _ in initialSettings do
		table.insert(initialSortedSaves, saveName)
	end
	table.sort(initialSortedSaves)
	sortedSaves:set(initialSortedSaves)

	scope:Observer(saves):onChange(function()
		local currentSaves = scope.peek(saves)
		local saveNames = {}
		for saveName, _ in currentSaves do
			table.insert(saveNames, saveName)
		end
		table.sort(saveNames)
		sortedSaves:set(saveNames)
		local success, data = pcall(function()
			plugin:SetSetting("RT_EVC_Saves", currentSaves)
			return plugin:GetSetting("RT_EVC_Saves")
		end)

		if success == false or utils.compareTables(data, currentSaves) == false then
			log.warn("Failed to save saves", success, data, currentSaves)
			local secondSuccess, _ = pcall(function()
				local saveScript = Instance.new("Script")
				saveScript.Name = "FAILED TO SAVE PLEASE SAVE THIS EMERGENCY BACKUP"
				saveScript.Source = "--EMERGENCY SAVE, CONTACT SUPPORT FOR HELP TO GET SAVES BACK\nreturn "
					.. LuaEncode(currentSaves, {})
				saveScript.Parent = game
				local currentSelection = Selection:Get()
				Selection:Set({ saveScript })
				task.wait(0.1)
				plugin:PromptSaveSelection(saveScript.Name)
				task.wait(0.1)
				Selection:Set(currentSelection)
				saveScript:Destroy()
			end)

			if secondSuccess == true then
				log.error("FAILED TO SAVE SAVES, EMERGENCY BACKUP CREATED")
			else
				log.info(currentSaves)
				log.error("FAILED TO CREATE EMERGENCY BACKUP, PLEASE COPY AND PASTE THE ABOVE TABLE INSTEAD")
			end
		end
	end)

	local newSaveName = scope:Value("")
	-- Parent Size: 3840, 2160
	local savePopup: Fusion.Value<Instance?> = scope:Value(nil)
	return savePopup:set(scope:base {
		Size = UDim2.fromScale(0.234375, 0.4282407407), -- 900, 925
		BackgroundColor3 = currentTheme.colors.base,
		Border = 1,
		CornerRadius = UDim.new(0, 15),
		ZIndex = 5001,

		[Fusion.Children] = {
			scope:base {
				Size = UDim2.fromScale(1, 0.0540540541), -- x, 50
				AnchorPoint = Vector2.new(0.5, 0),
				Position = UDim2.fromScale(0.5, 0.0162162162), -- x, 15
				BackgroundTransparency = 1,

				[Fusion.Children] = {
					scope:New("UIListLayout") {
						Padding = UDim.new(0.0333333333, 0),
						FillDirection = Enum.FillDirection.Horizontal,
						HorizontalAlignment = Enum.HorizontalAlignment.Center,
						SortOrder = Enum.SortOrder.LayoutOrder,
					},

					scope:textBox {
						Size = UDim2.fromScale(0.3333333333, 1),
						MaxSize = Vector2.new(300, 50),
						BackgroundColor3 = currentTheme.colors.crust,
						CornerRadius = UDim.new(0.2, 0),
						Border = 1,
						PlaceholderText = "New Save Name",
						[Fusion.Out "Text"] = newSaveName,
						TextScaled = true,
						MaxTextSize = 30,
						FontWeight = Enum.FontWeight.Regular,
						TextXAlignment = Enum.TextXAlignment.Left,
						LayoutOrder = 1,
						PaddingBottom = UDim.new(0.2, 0),
						PaddingTop = UDim.new(0.2, 0),
						PaddingLeft = UDim.new(0.0333333333, 0),
						PaddingRight = UDim.new(0.0333333333, 0),
					},

					scope:textButton {
						Size = UDim2.fromScale(0.1944444444, 1),
						MaxSize = Vector2.new(175, 50),
						BackgroundColor3 = currentTheme.colors.crust,
						CornerRadius = UDim.new(0.2, 0),
						Border = 2,
						Text = "Add",
						TextScaled = true,
						MaxTextSize = 25,
						FontWeight = Enum.FontWeight.Bold,
						LayoutOrder = 2,
						Reactive = true,

						[Fusion.OnEvent "Activated"] = function()
							local currentPattern = scope.peek(props.CurrentPattern)
							if currentPattern == nil then
								return
							end

							local currentSaves = scope.peek(saves)
							local saveNames = {}
							for saveName, _ in currentSaves do
								table.insert(saveNames, saveName)
							end
							local name = scope.peek(newSaveName)
							name = name:gsub('[\\"%.\n]', "")
							name = testSaveName(name, saveNames, 0)
							currentSaves[name] = utils.deepCopy(currentPattern.pattern)

							-- local currentPopup = scope.peek(savePopup)
							-- if currentPopup then
							-- 	currentPopup.Parent = nil
							-- 	popup:removePopup()
							-- end

							saves:set(currentSaves)
						end,
					},

					scope:textButton {
						Size = UDim2.fromScale(0.1944444444, 1),
						MaxSize = Vector2.new(175, 50),
						BackgroundColor3 = currentTheme.colors.crust,
						CornerRadius = UDim.new(0.2, 0),
						Border = 2,
						Text = "Import",
						TextScaled = true,
						MaxTextSize = 25,
						FontWeight = Enum.FontWeight.Bold,
						LayoutOrder = 3,
						Reactive = true,
					},
				},
			},

			scope:list {
				Size = UDim2.fromScale(1, 0.8108108108), -- x, 750
				AnchorPoint = Vector2.new(0.5, 0),
				Position = UDim2.fromScale(0.5, 0.0864864865), -- x, 80
				BackgroundColor3 = currentTheme.colors.base,
				AlternateColor3 = currentTheme.colors.mantle,
				PrimaryColor = "Alternate" :: "Alternate",
				RowSize = UDim2.fromScale(1, 0.0810810811),
				Rows = scope:ForPairs(saves, function(use, scope: typeof(scope), name: string, value: types.pattern)
					local key = table.find(use(sortedSaves), name)
					if key == nil then
						return 1, {} :: Fusion.Child
					end
					local nameValue = scope:Value(name)

					local isDownloadHovered = scope:Value(false)
					local isTrashHovered = scope:Value(false)
					return key,
						scope:base {
							Name = name,
							Size = UDim2.fromScale(1, 1),
							BackgroundTransparency = 1,

							[Fusion.Children] = {
								scope:textBox {
									Size = UDim2.fromScale(0.2777777778, 0.6666666667),
									AnchorPoint = Vector2.new(0, 0.5),
									Position = UDim2.fromScale(0.0166666667, 0.5),
									BackgroundColor3 = currentTheme.colors.crust,
									CornerRadius = UDim.new(0.2, 0),
									Border = 1,
									TextScaled = true,
									MaxTextSize = 20,
									FontWeight = Enum.FontWeight.Regular,
									MaxSize = Vector2.new(300, 50),
									PaddingBottom = UDim.new(0.2, 0),
									PaddingTop = UDim.new(0.2, 0),
									PaddingLeft = UDim.new(0.04, 0),
									PaddingRight = UDim.new(0.04, 0),
									Text = nameValue,
									[Fusion.Out "Text"] = nameValue :: unknown,
									TextXAlignment = Enum.TextXAlignment.Left,
									[Fusion.OnEvent "FocusLost"] = function()
										local currentSaves = scope.peek(saves)
										local newName = scope.peek(nameValue)
										if newName == name then
											return
										end
										local saveNames = {}
										for saveName, _ in currentSaves do
											table.insert(saveNames, saveName)
										end
										newName = newName:gsub('[\\"%.\n]', "")
										newName = testSaveName(newName, saveNames, 0)
										nameValue:set(newName)
										currentSaves[newName] = currentSaves[name]
										currentSaves[name] = nil
										saves:set(currentSaves)
									end,
								},

								scope:base {
									Size = UDim2.fromScale(0.6722222222, 1), -- 605, y
									AnchorPoint = Vector2.new(1, 0.5),
									Position = UDim2.fromScale(0.9833333333, 0.5),
									BackgroundTransparency = 1,

									[Fusion.Children] = {
										scope:New("UIListLayout") {
											Padding = UDim.new(0.0166666667, 0),
											FillDirection = Enum.FillDirection.Horizontal,
											HorizontalAlignment = Enum.HorizontalAlignment.Right,
											VerticalAlignment = Enum.VerticalAlignment.Center,
											SortOrder = Enum.SortOrder.LayoutOrder,
										},

										scope:textButton {
											Size = UDim2.fromScale(0.2479338843, 0.6666666667),
											BackgroundColor3 = currentTheme.colors.crust,
											CornerRadius = UDim.new(0.2, 0),
											Border = 1,
											TextScaled = true,
											MaxTextSize = 20,
											FontWeight = Enum.FontWeight.Regular,
											Text = "Load",
											TextXAlignment = Enum.TextXAlignment.Center,
											LayoutOrder = 1,
											Reactive = true,

											[Fusion.OnEvent "Activated"] = function()
												local currentPopup = scope.peek(savePopup)
												local currentPattern = scope.peek(props.CurrentPattern)
												if currentPopup == nil or currentPattern == nil then
													return
												end
												-- currentPopup.Parent = nil
												popup:removePopup()
												popup:addPopup(scope, {
													title = "Load Pattern",
													description = `Are you sure you want to load {scope.peek(nameValue)}?\n<b>All currently unsaved data will be lost.</b>`,
													actions = {
														{
															text = "Cancel",
															type = "primary",
															key = 1,
															callback = function(newPopup)
																popup:removePopup(newPopup)
																popup:customPopup(scope, currentPopup)
															end,
															keybind = Enum.KeyCode.Escape,
														},
														{
															text = "Load",
															type = "danger",
															key = 2,
															callback = function(newPopup)
																popup:removePopup(newPopup)
																local value = utils.deepCopy(value)
																log.debug("Loading", value)
																props.CurrentPattern:set({
																	functionId = currentPattern.functionId,
																	patternId = currentPattern.patternId,
																	pattern = value,
																})
																if currentConfiguration ~= nil then
																	currentConfiguration.functions[currentPattern.functionId].patterns[currentPattern.patternId] =
																		value
																end
															end,
														},
													},
												})
											end,
										},

										scope:textButton {
											Size = UDim2.fromScale(0.2479338843, 0.6666666667),
											BackgroundColor3 = currentTheme.colors.crust,
											CornerRadius = UDim.new(0.2, 0),
											Border = 1,
											TextScaled = true,
											MaxTextSize = 20,
											FontWeight = Enum.FontWeight.Regular,
											Text = "Save",
											TextXAlignment = Enum.TextXAlignment.Center,
											LayoutOrder = 2,
											Reactive = true,

											[Fusion.OnEvent "Activated"] = function()
												local currentPopup = scope.peek(savePopup)
												local currentPattern = scope.peek(props.CurrentPattern)
												local currentSaves = scope.peek(saves)
												if currentPopup == nil or currentPattern == nil then
													return
												end
												-- currentPopup.Parent = nil
												popup:removePopup()
												popup:addPopup(scope, {
													title = "Overwrite Save",
													description = `Are you sure you want to overwrite {scope.peek(
														nameValue
													)}?\nAll currently saved data will be lost.`,
													actions = {
														{
															text = "Cancel",
															type = "primary",
															key = 1,
															callback = function(newPopup)
																popup:removePopup(newPopup)
																popup:customPopup(scope, currentPopup)
															end,
															keybind = Enum.KeyCode.Escape,
														},
														{
															text = "Overwrite",
															type = "danger",
															key = 2,
															callback = function(newPopup)
																popup:removePopup(newPopup)
																popup:customPopup(scope, currentPopup)
																currentSaves[name] =
																	utils.deepCopy(currentPattern.pattern)
																saves:set(currentSaves)
															end,
														},
													},
												})
											end,
										},

										scope:iconButton {
											Size = UDim2.fromScale(0.0595041322, 0.7666666667),
											BackgroundTransparency = 1,
											Image = scope:Computed(function(use)
												return if use(isDownloadHovered)
													then assets.images.redonUI.downloadFilled
													else assets.images.redonUI.download
											end),
											Reactive = true,
											ScaleType = Enum.ScaleType.Fit,
											LayoutOrder = 3,

											MouseEnter = function()
												isDownloadHovered:set(true)
											end,

											MouseLeave = function()
												isDownloadHovered:set(false)
											end,

											[Fusion.OnEvent "Activated"] = function() end,
										},

										scope:iconButton {
											Size = UDim2.fromScale(0.0661157025, 0.7666666667),
											BackgroundTransparency = 1,
											Image = scope:Computed(function(use)
												return if use(isTrashHovered)
													then assets.images.redonUI.trashFilled
													else assets.images.redonUI.trash
											end),
											Reactive = true,
											ScaleType = Enum.ScaleType.Fit,
											LayoutOrder = 4,

											MouseEnter = function()
												isTrashHovered:set(true)
											end,

											MouseLeave = function()
												isTrashHovered:set(false)
											end,

											[Fusion.OnEvent "Activated"] = function()
												local currentPopup = scope.peek(savePopup)
												local currentSaves = scope.peek(saves)
												if currentPopup == nil then
													return
												end
												-- currentPopup.Parent = nil
												popup:removePopup()
												popup:addPopup(scope, {
													title = "Delete Save",
													description = `Are you sure you want to delete {scope.peek(
														nameValue
													)}?\nAll currently saved data will be lost.`,
													actions = {
														{
															text = "Cancel",
															type = "primary",
															key = 1,
															callback = function(newPopup)
																popup:removePopup(newPopup)
																popup:customPopup(scope, currentPopup)
															end,
															keybind = Enum.KeyCode.Escape,
														},
														{
															text = "Delete",
															type = "danger",
															key = 2,
															callback = function(newPopup)
																popup:removePopup(newPopup)
																popup:customPopup(scope, currentPopup)
																currentSaves[name] = nil
																saves:set(currentSaves)
															end,
														},
													},
												})
											end,
										},
									},
								},
							},
						}
				end),
			},

			scope:base {
				Size = UDim2.fromScale(1, 0.0540540541), -- x, 50
				AnchorPoint = Vector2.new(0.5, 1),
				Position = UDim2.fromScale(0.5, 0.9837837838), -- x, 15
				BackgroundTransparency = 1,

				[Fusion.Children] = {
					scope:textButton {
						Size = UDim2.fromScale(0.3333333333, 1),
						AnchorPoint = Vector2.new(0.5, 0.5),
						Position = UDim2.fromScale(0.5, 0.5),
						MaxSize = Vector2.new(175, 50),
						BackgroundColor3 = currentTheme.colors.crust,
						CornerRadius = UDim.new(0.2, 0),
						Border = 2,
						Text = "Done",
						TextScaled = true,
						MaxTextSize = 30,
						FontWeight = Enum.FontWeight.Bold,
						Reactive = true,

						[Fusion.OnEvent "Activated"] = function()
							local currentPopup = scope.peek(savePopup)
							if currentPopup then
								-- currentPopup.Parent = nil
								popup:removePopup()
							end
						end,
					},
				},
			},
		},
	}) :: Instance
end