--!nonstrict
local Knob = script.Parent
local Control = Knob.Parent
local App = Control.Parent
local UIBlox = App.Parent
local Packages = UIBlox.Parent

local Roact = require(Packages.Roact)
local t = require(Packages.t)

local RoactGamepad = require(Packages.RoactGamepad)
local Images = require(App.ImageSet.Images)
local ImageSetComponent = require(UIBlox.Core.ImageSet.ImageSetComponent)
local Interactable = require(UIBlox.Core.Control.Interactable)
local ControlState = require(UIBlox.Core.Control.Enum.ControlState)
local withStyle = require(UIBlox.Core.Style.withStyle)
local validateColor = require(UIBlox.Core.Style.Validator.validateColorInfo)
local BaseKnob = Roact.Component:extend("BaseKnob")

-- local validateColor = t.interface({
-- 	Color = t.Color3,
-- 	Transparency = t.number,
-- })

local ShadowColorMap = {
	[ControlState.Default] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.7,
	},
	[ControlState.Hover] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.5,
	},
}

local ShadowSizeMap = {
	[ControlState.Default] = UDim2.fromOffset(48, 48),
	[ControlState.Hover] = UDim2.fromOffset(48, 48),
	[ControlState.Pressed] = UDim2.fromOffset(0, 0),
	[ControlState.Disabled] = UDim2.fromOffset(0, 0),
	[ControlState.Selected] = UDim2.fromOffset(52, 52),
	[ControlState.SelectedPressed] = UDim2.fromOffset(42, 42),
}

local ShadowImageMap = {
	[ControlState.Default] = "component_assets/dropshadow_28",
	[ControlState.Hover] = "component_assets/dropshadow_28",
	[ControlState.Selected] = "component_assets/circle_52_stroke_3",
	[ControlState.SelectedPressed] = "component_assets/circle_42_stroke_3",
}

BaseKnob.validateProps = t.interface({
	-- Triggered when style state changes
	onStateChanged = t.optional(t.callback),

	-- If this component is in disabled state & disabled style
	isDisabled = t.optional(t.boolean),

	-- A Boolean value that determines whether user events are ignored and sink input
	-- If user can interact with this component
	userInteractionEnabled = t.optional(t.boolean),

	-- Triggered when user activate this component with mouse / touch / gamepad
	onActivated = t.optional(t.callback),
	-- The anchor point of the circle, default to its center
	anchorPoint = t.optional(t.Vector2),
	-- The layout order number for UIListLayout
	layoutOrder = t.optional(t.number),
	-- The position of this component, use with anchor point together
	position = t.optional(t.UDim2),

	colorMap = t.strictInterface({
		[ControlState.Default] = validateColor,
		[ControlState.Hover] = validateColor,
		[ControlState.Pressed] = validateColor,
		[ControlState.Disabled] = validateColor,
		[ControlState.Selected] = validateColor,
		[ControlState.SelectedPressed] = validateColor,
	}),

	-- Gamepad support related props
	NextSelectionLeft = t.optional(t.table),
	NextSelectionRight = t.optional(t.table),
	NextSelectionUp = t.optional(t.table),
	NextSelectionDown = t.optional(t.table),
	controlRef = t.optional(t.table),

	-- Whether to enable RoactGamepad functionality
	isRoactGamepadEnabled = t.optional(t.boolean),
})

BaseKnob.defaultProps = {
	anchorPoint = Vector2.new(0.5, 0.5),
	userInteractionEnabled = true,
	isDisabled = false,
	isRoactGamepadEnabled = true,
}

function BaseKnob:init()
	self:setState({
		controlState = ControlState.Initialize,
	})

	self.onStateChanged = function(oldState, newState)
		self:setState({
			controlState = newState,
		})
		if self.props.onStateChanged then
			self.props.onStateChanged(oldState, newState)
		end
	end
end

function BaseKnob:render()
	return withStyle(function(style)
		local color = self.props.colorMap[self.state.controlState] or self.props.colorMap[ControlState.Default]
		local shadowSize = ShadowSizeMap[self.state.controlState] or ShadowSizeMap[ControlState.Default]
		local shadowImage = ShadowImageMap[self.state.controlState] or ShadowImageMap[ControlState.Default]
		local isGamepadSelected = self.state.controlState == ControlState.Selected
			or self.state.controlState == ControlState.SelectedPressed
		local shadowColor = ShadowColorMap[self.state.controlState] or ShadowColorMap[ControlState.Default]
		if isGamepadSelected then
			shadowColor = style.Theme.SelectionCursor
		end

		return Roact.createElement("Frame", {
			AnchorPoint = self.props.anchorPoint,
			LayoutOrder = self.props.layoutOrder,
			Position = self.props.position,
			BackgroundTransparency = 1,
			Size = UDim2.fromOffset(28, 28),
		}, {
			KnobShadow = Roact.createElement(ImageSetComponent.Label, {
				Size = shadowSize,
				Position = UDim2.new(0.5, 0, 0.5, not isGamepadSelected and 2 or 0),
				AnchorPoint = Vector2.new(0.5, 0.5),
				Image = Images[shadowImage],
				ImageColor3 = shadowColor.Color,
				ImageTransparency = shadowColor.Transparency,
				Active = true,
				BackgroundTransparency = 1,
			}),
			KnobButton = Roact.createElement(
				if self.props.isRoactGamepadEnabled then RoactGamepad.Focusable[Interactable] else Interactable,
				{
					Size = UDim2.fromScale(1, 1),
					isDisabled = self.props.isDisabled,
					onStateChanged = self.onStateChanged,
					userInteractionEnabled = self.props.userInteractionEnabled,
					BackgroundTransparency = 1,
					Image = Images["component_assets/circle_29"],
					ImageColor3 = color.Color,
					ImageTransparency = color.Transparency,
					[Roact.Ref] = self.props.forwardedRef,
					[Roact.Event.Activated] = self.props.onActivated,
					NextSelectionLeft = self.props.NextSelectionLeft,
					NextSelectionRight = self.props.NextSelectionRight,
					NextSelectionUp = self.props.NextSelectionUp,
					NextSelectionDown = self.props.NextSelectionDown,
				}
			),
		})
	end)
end

return BaseKnob
