local OptionBindingCtrl = class("OptionBindingCtrl", BaseCtrl)
local InputManager = CS.InputManager
local GamepadUIManager = require("GameCore.Module.GamepadUIManager")
local BasicDevice = {
	Keyboard = 1,
	Mouse = 2,
	Gamepad = 3
}
local ImageKey = {backspace = 1, enter = 2}
local IllegalKeyboardKey = {
	"Caps Lock",
	"Left Windows",
	"Right Windows",
	"Prnt Scrn",
	"Scroll Lock",
	"Break",
	"Num Lock",
	"Alt",
	"Left Alt",
	"Right Alt",
	"Esc",
	"Application",
	"B"
}
local LegalGamepadKey = {
	"buttonSouth",
	"buttonWest",
	"buttonEast",
	"buttonNorth",
	"leftShoulder",
	"rightShoulder",
	"leftTrigger",
	"rightTrigger"
}
OptionBindingCtrl._mapNodeConfig = {
	txtOptionTitle = {sComponentName = "TMP_Text"},
	btnBind = {
		sComponentName = "UIButton",
		callback = "OnBtnClick_Bind"
	},
	Placeholder = {},
	goBind = {},
	bindBg = {},
	holderBg = {},
	Keyboard = {},
	goKey = {},
	imgKeyboard = {sComponentName = "Image"},
	txtKeyboard = {sComponentName = "TMP_Text"},
	Mouse = {},
	imgMouse = {sComponentName = "Image"},
	Gamepad = {},
	imgGamepad = {sComponentName = "Image"}
}
OptionBindingCtrl._mapEventConfig = {
	LuaEventName_KeyboardButtonPress = "OnEvent_KeyboardButtonPress",
	LuaEventName_MouseButtonPress = "OnEvent_MouseButtonPress",
	LuaEventName_GamepadButtonPress = "OnEvent_GamepadButtonPress",
	SettingsSwitchBind = "OnEvent_SwitchBind"
}
function OptionBindingCtrl:SetText(sTitle)
	NovaAPI.SetTMPText(self._mapNode.txtOptionTitle, sTitle)
end
function OptionBindingCtrl:Init(nType, sAction, sName, sDisplayName, bPS)
	self.bActiveBinding = false
	self.nDeviceType = nType
	self.sAction = sAction
	self.sName = sName
	self.sDisplayName = sDisplayName
	self.bPS = bPS
	self:SwitchState(false)
	self:RefreshButton()
end
function OptionBindingCtrl:SwitchState(bholder)
	self._mapNode.Placeholder:SetActive(bholder)
	self._mapNode.holderBg:SetActive(bholder)
	self._mapNode.goBind:SetActive(not bholder)
	self._mapNode.bindBg:SetActive(not bholder)
end
function OptionBindingCtrl:ChangeGamepad(bPS)
	self.bPS = bPS
	if self.bActiveBinding then
		return
	end
	self:RefreshButton()
end
function OptionBindingCtrl:RefreshButton()
	self._mapNode.Keyboard:SetActive(self.nDeviceType == BasicDevice.Keyboard)
	self._mapNode.Mouse:SetActive(self.nDeviceType == BasicDevice.Mouse)
	self._mapNode.Gamepad:SetActive(self.nDeviceType == BasicDevice.Gamepad)
	if self.nDeviceType == BasicDevice.Keyboard then
		if ImageKey[self.sName] then
			self._mapNode.imgKeyboard.gameObject:SetActive(true)
			self._mapNode.goKey:SetActive(false)
			local sIcon = ConfigTable.GetField("GamepadButton", self.sName, "XboxIcon")
			self:SetPngSprite(self._mapNode.imgKeyboard, sIcon)
			NovaAPI.SetImageNativeSize(self._mapNode.imgKeyboard)
		else
			self._mapNode.imgKeyboard.gameObject:SetActive(false)
			self._mapNode.goKey:SetActive(true)
			local sName = GamepadUIManager.GetInputName({
				name = self.sName,
				displayName = self.sDisplayName
			})
			NovaAPI.SetTMPText(self._mapNode.txtKeyboard, sName)
		end
	elseif self.nDeviceType == BasicDevice.Mouse then
		local sIcon = ConfigTable.GetField("GamepadButton", self.sName, "XboxIcon")
		self:SetPngSprite(self._mapNode.imgMouse, sIcon)
	elseif self.nDeviceType == BasicDevice.Gamepad then
		local sIcon
		if self.bPS then
			sIcon = ConfigTable.GetField("GamepadButton", self.sName, "PlayStationIcon")
		else
			sIcon = ConfigTable.GetField("GamepadButton", self.sName, "XboxIcon")
		end
		self:SetPngSprite(self._mapNode.imgGamepad, sIcon)
	end
end
function OptionBindingCtrl:OpenDeviceWarning()
	EventManager.Hit(EventId.OpenMessageBox, ConfigTable.GetUIText("Settings_Tip_IllegalDevice"))
	self:QuitBinding()
end
function OptionBindingCtrl:OpenKeyWarning()
	EventManager.Hit(EventId.OpenMessageBox, ConfigTable.GetUIText("Settings_Tip_IllegalInput"))
	self:QuitBinding()
end
function OptionBindingCtrl:OpenConflictWarning(sBeforeAction, inputInfo, nType)
	local sActionName = ConfigTable.GetUIText("Action_" .. sBeforeAction)
	local sTip = ConfigTable.GetUIText("Settings_Tip_ConflictInput") or ""
	local msg = {
		nType = AllEnum.MessageBox.Confirm,
		sContent = orderedFormat(sTip, sActionName),
		callbackConfirm = function()
			EventManager.Hit("SettingsSwitchBind", self.nDeviceType, inputInfo, {
				name = self.sName,
				displayName = self.sDisplayName
			})
			self:SwitchState(false)
			self.nDeviceType = nType
			self.sName = inputInfo.name
			self.sDisplayName = inputInfo.displayName
			self:UpdateBindConfig(inputInfo, nType)
			self:RefreshButton()
		end,
		callbackCancel = function()
			self:SwitchState(false)
		end,
		bBlur = false
	}
	local wait = function()
		coroutine.yield(CS.UnityEngine.WaitForEndOfFrame())
		self.bActiveBinding = false
		EventManager.Hit(EventId.BlockInput, false)
		InputManager.Instance.IsVirtualMouseEnabled = true
		EventManager.Hit(EventId.OpenMessageBox, msg)
	end
	cs_coroutine.start(wait)
end
function OptionBindingCtrl:OnBindingSuccess(inputInfo, nType)
	self.nDeviceType = nType
	self.sName = inputInfo.name
	self.sDisplayName = inputInfo.displayName
	self:UpdateBindConfig(inputInfo, nType)
	self:RefreshButton()
	self:QuitBinding()
end
function OptionBindingCtrl:UpdateBindConfig(inputInfo, nType)
	if nType == BasicDevice.Gamepad then
		self._panel.mapGamepadBind[self.sAction] = inputInfo.name
		EventManager.Hit("SettingsRefreshDisplay", self.sAction, inputInfo.name)
	else
		self._panel.mapKeyboardBind[self.sAction] = {
			name = inputInfo.name,
			displayName = inputInfo.displayName
		}
	end
end
function OptionBindingCtrl:QuitBinding()
	self.bActiveBinding = false
	self:SwitchState(false)
	InputManager.Instance.IsVirtualMouseEnabled = true
	self._mapNode.btnBind.interactable = false
	self:AddTimer(1, 0.4, function()
		self._mapNode.btnBind.interactable = true
		EventManager.Hit(EventId.BlockInput, false)
	end, true, true, true)
end
function OptionBindingCtrl:OnBtnClick_Bind()
	self.bActiveBinding = true
	self:SwitchState(true)
	EventManager.Hit(EventId.BlockInput, true)
	InputManager.Instance.IsVirtualMouseEnabled = false
end
function OptionBindingCtrl:OnEvent_KeyboardButtonPress(inputInfo)
	if not self.bActiveBinding then
		return
	end
	if self.nDeviceType == BasicDevice.Gamepad then
		self:OpenDeviceWarning()
		return
	end
	if table.indexof(IllegalKeyboardKey, inputInfo.displayName) ~= 0 then
		self:OpenKeyWarning()
		return
	end
	if inputInfo.name == self.sName then
		self:QuitBinding()
		return
	end
	local sBeforeAction
	for k, v in pairs(self._panel.mapKeyboardBind) do
		if v.name == inputInfo.name then
			sBeforeAction = k
		end
	end
	if sBeforeAction then
		self:OpenConflictWarning(sBeforeAction, inputInfo, BasicDevice.Keyboard)
		return
	end
	self:OnBindingSuccess(inputInfo, BasicDevice.Keyboard)
end
function OptionBindingCtrl:OnEvent_MouseButtonPress(inputInfo)
	if not self.bActiveBinding then
		return
	end
	if self.nDeviceType == BasicDevice.Gamepad then
		self:OpenDeviceWarning()
		return
	end
	if inputInfo.name == self.sName then
		self:QuitBinding()
		return
	end
	local sBeforeAction
	for k, v in pairs(self._panel.mapKeyboardBind) do
		if v.name == inputInfo.name then
			sBeforeAction = k
		end
	end
	if sBeforeAction then
		self:OpenConflictWarning(sBeforeAction, inputInfo, BasicDevice.Mouse)
		return
	end
	self:OnBindingSuccess(inputInfo, BasicDevice.Mouse)
end
function OptionBindingCtrl:OnEvent_GamepadButtonPress(inputInfo)
	if not self.bActiveBinding then
		return
	end
	if self.nDeviceType ~= BasicDevice.Gamepad then
		self:OpenDeviceWarning()
		return
	end
	if inputInfo.name == "leftTriggerButton" then
		inputInfo.name = "leftTrigger"
	elseif inputInfo.name == "rightTriggerButton" then
		inputInfo.name = "rightTrigger"
	end
	if table.indexof(LegalGamepadKey, inputInfo.name) == 0 then
		self:OpenKeyWarning()
		return
	end
	if inputInfo.name == self.sName then
		self:QuitBinding()
		return
	end
	local sBeforeAction = table.keyof(self._panel.mapGamepadBind, inputInfo.name)
	if sBeforeAction then
		self:OpenConflictWarning(sBeforeAction, inputInfo, BasicDevice.Gamepad)
		return
	end
	self:OnBindingSuccess(inputInfo, BasicDevice.Gamepad)
end
function OptionBindingCtrl:OnEvent_SwitchBind(nType, inputInfoBefore, inputInfo)
	if not self.sName or self.sName ~= inputInfoBefore.name then
		return
	end
	self.nDeviceType = nType
	self.sName = inputInfo.name
	self.sDisplayName = inputInfo.displayName
	self:UpdateBindConfig(inputInfo, nType)
	self:RefreshButton()
end
return OptionBindingCtrl
