---@class StdUi
local StdUi = LibStub and LibStub('StdUi', true)
if not StdUi then return end

local module, version = 'Checkbox', 5
if not StdUi:UpgradeNeeded(module, version) then return end

----------------------------------------------------
--- Checkbox
----------------------------------------------------

local CheckboxMethods = {
	--- Set checkbox state
	---
	---@param flag boolean
	---@param internal boolean - indicates to not run OnValueChanged
	SetChecked = function(self, flag, internal)
		self.isChecked = flag

		if not internal and self.OnValueChanged then self:OnValueChanged(flag, self.value) end

		if not flag then
			self.checkedTexture:Hide()
			self.disabledCheckedTexture:Hide()
			return
		end

		if self.isDisabled then
			self.checkedTexture:Hide()
			self.disabledCheckedTexture:Show()
		else
			self.checkedTexture:Show()
			self.disabledCheckedTexture:Hide()
		end
	end,

	GetChecked = function(self)
		return self.isChecked
	end,

	SetText = function(self, t)
		self.text:SetText(t)
	end,

	SetValue = function(self, value)
		self.value = value
	end,

	GetValue = function(self)
		if self:GetChecked() then
			return self.value
		else
			return nil
		end
	end,

	Disable = function(self)
		self.isDisabled = true
		self:SetChecked(self.isChecked)
	end,

	Enable = function(self)
		self.isDisabled = false
		self:SetChecked(self.isChecked)
	end,

	AutoWidth = function(self)
		self:SetWidth(self.target:GetWidth() + 15 + self.text:GetWidth())
	end,
}

local CheckboxEvents = {
	OnClick = function(self)
		if not self.isDisabled then self:SetChecked(not self:GetChecked()) end
	end,
}

---@return CheckButton
function StdUi:Checkbox(parent, text, width, height)
	local checkbox = CreateFrame('Button', nil, parent)
	checkbox.stdUi = self

	checkbox:EnableMouse(true)
	self:SetObjSize(checkbox, width, height or 20)
	self:InitWidget(checkbox)

	checkbox.target = self:Panel(checkbox, 16, 16)
	checkbox.target.stdUi = self
	checkbox.target:SetPoint('LEFT', 0, 0)

	checkbox.value = true
	checkbox.isChecked = false

	checkbox.text = self:Label(checkbox, text)
	checkbox.text:SetPoint('LEFT', checkbox.target, 'RIGHT', 5, 0)
	checkbox.text:SetPoint('RIGHT', checkbox, 'RIGHT', -5, 0)
	checkbox.target.text = checkbox.text -- reference for disabled

	checkbox.checkedTexture = self:Texture(checkbox.target, nil, nil, [[Interface\Buttons\UI-CheckBox-Check]])
	checkbox.checkedTexture:SetAllPoints()
	checkbox.checkedTexture:Hide()

	checkbox.disabledCheckedTexture = self:Texture(checkbox.target, nil, nil, [[Interface\Buttons\UI-CheckBox-Check-Disabled]])
	checkbox.disabledCheckedTexture:SetAllPoints()
	checkbox.disabledCheckedTexture:Hide()

	for k, v in pairs(CheckboxMethods) do
		checkbox[k] = v
	end

	self:ApplyBackdrop(checkbox.target)
	self:HookDisabledBackdrop(checkbox)
	self:HookHoverBorder(checkbox)

	if width == nil then checkbox:AutoWidth() end

	for k, v in pairs(CheckboxEvents) do
		checkbox:SetScript(k, v)
	end

	return checkbox
end

----------------------------------------------------
--- IconCheckbox
----------------------------------------------------

function StdUi:IconCheckbox(parent, icon, text, width, height, iconSize)
	iconSize = iconSize or 16
	local checkbox = self:Checkbox(parent, text, width, height)
	checkbox.icon = self:Texture(checkbox, iconSize, iconSize, icon)
	checkbox.icon:SetPoint('LEFT', checkbox.target, 'RIGHT', 5, 0)

	checkbox.text:ClearAllPoints()
	checkbox.text:SetPoint('LEFT', checkbox.target, 'RIGHT', iconSize + 5, 0)
	checkbox.text:SetPoint('RIGHT', checkbox, 'RIGHT', -5, 0)

	return checkbox
end

----------------------------------------------------
--- Radio
----------------------------------------------------

local RadioEvents = {
	OnClick = function(self)
		if not self.isDisabled then self:SetChecked(true) end
	end,
}

---@return CheckButton
function StdUi:Radio(parent, text, groupName, width, height)
	local radio = self:Checkbox(parent, text, width, height)

	radio.checkedTexture = self:Texture(radio.target, nil, nil, [[Interface\Buttons\UI-RadioButton]])
	radio.checkedTexture:SetAllPoints(radio.target)
	radio.checkedTexture:Hide()
	radio.checkedTexture:SetTexCoord(0.25, 0.5, 0, 1)

	radio.disabledCheckedTexture = self:Texture(radio.target, nil, nil, [[Interface\Buttons\UI-RadioButton]])
	radio.disabledCheckedTexture:SetAllPoints(radio.target)
	radio.disabledCheckedTexture:Hide()
	radio.disabledCheckedTexture:SetTexCoord(0.75, 1, 0, 1)

	for k, v in pairs(RadioEvents) do
		radio:SetScript(k, v)
	end

	if groupName then self:AddToRadioGroup(radio, groupName) end

	return radio
end

StdUi.radioGroups = {}
StdUi.radioGroupValues = {}

---@return CheckButton[]
function StdUi:RadioGroup(groupName)
	if not self.radioGroups[groupName] then self.radioGroups[groupName] = {} end

	if not self.radioGroupValues[groupName] then self.radioGroupValues[groupName] = {} end

	return self.radioGroups[groupName]
end

function StdUi:GetRadioGroupValue(groupName)
	local group = self:RadioGroup(groupName)

	for i = 1, #group do
		local radio = group[i]
		if radio:GetChecked() then return radio:GetValue() end
	end

	return nil
end

function StdUi:SetRadioGroupValue(groupName, value)
	local group = self:RadioGroup(groupName)

	for i = 1, #group do
		local radio = group[i]
		radio:SetChecked(radio.value == value)
	end

	return nil
end

local radioGroupOnValueChanged = function(radio)
	radio.notified = true
	local group = radio.radioGroup
	local groupName = radio.radioGroupName

	-- We must get all notifications from group
	for i = 1, #group do
		if not group[i].notified then return end
	end

	local newValue = radio.stdUi:GetRadioGroupValue(groupName)
	if radio.stdUi.radioGroupValues[groupName] ~= newValue then radio.OnValueChangedCallback(newValue, groupName) end
	radio.stdUi.radioGroupValues[groupName] = newValue

	for i = 1, #group do
		group[i].notified = false
	end
end

function StdUi:OnRadioGroupValueChanged(groupName, callback)
	local group = self:RadioGroup(groupName)

	for i = 1, #group do
		local radio = group[i]
		radio.OnValueChangedCallback = callback
		radio.OnValueChanged = radioGroupOnValueChanged
	end

	return nil
end

local RadioGroupEvents = {
	OnClick = function(radio)
		for i = 1, #radio.radioGroup do
			local otherRadio = radio.radioGroup[i]

			if otherRadio ~= radio then otherRadio:SetChecked(false) end
		end
	end,
}

function StdUi:AddToRadioGroup(radio, groupName)
	local group = self:RadioGroup(groupName)
	tinsert(group, radio)
	radio.radioGroup = group
	radio.radioGroupName = groupName

	for k, v in pairs(RadioGroupEvents) do
		radio:HookScript(k, v)
	end
end

StdUi:RegisterModule(module, version)
