local _, ns = ...
local SlickUI = ns.SlickUI
local Theme = SlickUI.Theme

local GroupControls = {}
SlickUI.GroupControls = GroupControls

local function IsLeader()
	return not IsInGroup() or UnitIsGroupLeader("player") or UnitIsGroupAssistant("player")
end

local function ConvertGroup(toRaid)
	if not IsInGroup() then SlickUI:Print("You must be in a group first."); return end
	if not UnitIsGroupLeader("player") then SlickUI:Print("Only the group leader can convert the group."); return end
	local converter
	if C_PartyInfo then converter = toRaid and C_PartyInfo.ConvertToRaid or C_PartyInfo.ConvertToParty end
	if type(converter) ~= "function" then converter = toRaid and ConvertToRaid or ConvertToParty end
	if type(converter) ~= "function" then SlickUI:Print("WoW's group conversion control is unavailable."); return end
	local ok, message = pcall(converter)
	if not ok then SlickUI:Print("Group conversion failed: " .. tostring(message)) end
end

local function CreateButton(parent, text, width, onClick)
	local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
	button:SetSize(width, 24)
	button:SetText(text)
	if onClick then button:SetScript("OnClick", onClick) end
	return button
end

function GroupControls:Refresh()
	if not self.Frame then return end
	if InCombatLockdown() then
		self.PendingRefresh = true
		return false
	end
	local enabled = SlickUI.DB.groupControls.enabled == true
	local shown = SlickUI.DB.groupControls.shown ~= false
	self.Frame:SetShown(enabled and shown)
	if self.MarkerPanel and (not enabled or not shown) then self.MarkerPanel:Hide() end
	if not enabled then return end
	local leader = IsLeader()
	local groupLeader = UnitIsGroupLeader("player") == true
	self.Ready:SetEnabled(leader and IsInGroup())
	self.Pull:SetEnabled(leader and IsInGroup())
	self.Role:SetEnabled(leader and IsInGroup())
	self.Raid:SetEnabled(groupLeader and IsInGroup() and not IsInRaid())
	self.Party:SetEnabled(groupLeader and IsInRaid())
	local activeKey = C_ChallengeMode and C_ChallengeMode.GetActiveChallengeMapID and (C_ChallengeMode.GetActiveChallengeMapID() or 0) > 0
	self.Abandon:SetShown(activeKey)
	self.Frame:SetWidth(activeKey and 462 or 396)
	self.PendingRefresh = false
	return true
end

local function CreateSecureMacroButton(parent, text, macroText, tooltip)
	local button = CreateFrame("Button", nil, parent, "SecureActionButtonTemplate,UIPanelButtonTemplate")
	button:SetSize(42, 22)
	button:SetText(text)
	button:RegisterForClicks("AnyUp", "AnyDown")
	button:SetAttribute("type", "macro")
	button:SetAttribute("macrotext", macroText)
	button:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_TOP")
		GameTooltip:SetText(tooltip)
		GameTooltip:Show()
	end)
	button:SetScript("OnLeave", GameTooltip_Hide)
	return button
end

local function CreateGroundMarkerIcon(parent, iconIndex, worldMarkerIndex, name)
	local button = CreateFrame("Button", nil, parent, "SecureActionButtonTemplate")
	button:SetSize(24, 24)
	button:RegisterForClicks("AnyUp", "AnyDown")
	button:SetAttribute("type", "macro")
	button:SetAttribute("macrotext", "/wm " .. worldMarkerIndex)
	local texture = button:CreateTexture(nil, "ARTWORK")
	texture:SetAllPoints()
	texture:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
	local column = (iconIndex - 1) % 4
	local row = math.floor((iconIndex - 1) / 4)
	texture:SetTexCoord(column * 0.25, (column + 1) * 0.25, row * 0.25, (row + 1) * 0.25)
	button:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")
	button:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_TOP")
		GameTooltip:SetText("Place " .. name .. " ground marker")
		GameTooltip:Show()
	end)
	button:SetScript("OnLeave", GameTooltip_Hide)
	return button
end

local function CreateMarkerPanelIcon(parent, iconIndex, macroText, tooltip)
	local button = CreateFrame("Button", nil, parent, "SecureActionButtonTemplate")
	button:SetSize(26, 26)
	button:RegisterForClicks("AnyUp", "AnyDown")
	button:SetAttribute("type", "macro")
	button:SetAttribute("macrotext", macroText)
	local texture = button:CreateTexture(nil, "ARTWORK")
	texture:SetAllPoints()
	texture:SetTexture("Interface\\TargetingFrame\\UI-RaidTargetingIcons")
	local column = (iconIndex - 1) % 4
	local row = math.floor((iconIndex - 1) / 4)
	texture:SetTexCoord(column * 0.25, (column + 1) * 0.25, row * 0.25, (row + 1) * 0.25)
	button:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")
	button:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_TOP")
		GameTooltip:SetText(tooltip)
		GameTooltip:Show()
	end)
	button:SetScript("OnLeave", GameTooltip_Hide)
	return button
end

function GroupControls:ToggleMarkerPanel()
	if InCombatLockdown() then
		SlickUI:Print("Open the marker panel before combat; its marker buttons remain usable during combat.")
		return
	end
	self.MarkerPanel:SetShown(not self.MarkerPanel:IsShown())
end

function GroupControls:CreateMarkerPanel(owner)
	local panel = CreateFrame("Frame", "SlickUIGroupMarkerPanel", UIParent, "BackdropTemplate")
	panel:SetSize(414, 82)
	panel:SetFrameStrata("DIALOG")
	panel:SetClampedToScreen(true)
	panel:SetPoint("BOTTOMLEFT", owner:GetParent(), "TOPLEFT", 0, 5)
	Theme:CreatePanel(panel)

	local targetLabel = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
	targetLabel:SetPoint("TOPLEFT", 8, -8)
	targetLabel:SetText("Target")
	local worldLabel = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
	worldLabel:SetPoint("TOPLEFT", 8, -45)
	worldLabel:SetText("World")

	local targetNames = { "Star", "Circle", "Diamond", "Triangle", "Moon", "Square", "Cross", "Skull" }
	local worldNames = { "Square", "Triangle", "Diamond", "Cross", "Star", "Circle", "Moon", "Skull" }
	local worldIconIndices = { 6, 4, 3, 7, 1, 2, 5, 8 }
	for index, name in ipairs(targetNames) do
		local target = CreateMarkerPanelIcon(panel, index, "/tm " .. index, "Set target marker: " .. name)
		target:SetPoint("TOPLEFT", 55 + ((index - 1) * 39), -5)
		local world = CreateMarkerPanelIcon(panel, worldIconIndices[index], "/wm " .. index, "Place world marker: " .. worldNames[index])
		world:SetPoint("TOPLEFT", 55 + ((index - 1) * 39), -42)
	end

	local clearTarget = CreateSecureMacroButton(panel, "X", "/tm 0", "Clear the target marker")
	clearTarget:SetPoint("TOPRIGHT", -7, -5)
	local clearWorld = CreateSecureMacroButton(panel, "X", "/cwm all", "Clear all world markers")
	clearWorld:SetPoint("TOPRIGHT", -7, -42)
	panel:Hide()
	self.MarkerPanel = panel
end

function GroupControls:CreateFrame()
	local frame = CreateFrame("Frame", "SlickUIGroupControls", UIParent)
	frame:SetSize(396, 68); frame:SetFrameStrata("MEDIUM"); frame:SetClampedToScreen(true)
	Theme:CreatePanel(frame)
	local ready = CreateButton(frame, "Ready", 58, function() if IsLeader() and IsInGroup() and DoReadyCheck then DoReadyCheck() end end)
	ready:SetPoint("BOTTOMLEFT", 7, 7)
	local pull = CreateButton(frame, "Pull", 50, function()
		if IsLeader() and IsInGroup() and C_PartyInfo and C_PartyInfo.DoCountdown then C_PartyInfo.DoCountdown(SlickUI.DB.groupControls.pullSeconds or 10) end
	end)
	pull:SetPoint("LEFT", ready, "RIGHT", 3, 0)
	local role = CreateButton(frame, "Roles", 54, function() if IsLeader() and IsInGroup() and InitiateRolePoll then InitiateRolePoll() end end)
	role:SetPoint("LEFT", pull, "RIGHT", 3, 0)
	local raid = CreateButton(frame, "Raid", 48, function() ConvertGroup(true) end)
	raid:SetPoint("LEFT", role, "RIGHT", 3, 0)
	local party = CreateButton(frame, "Party", 52, function() ConvertGroup(false) end)
	party:SetPoint("LEFT", raid, "RIGHT", 3, 0)
	local markers = CreateButton(frame, "Markers", 72, function() GroupControls:ToggleMarkerPanel() end)
	markers:SetPoint("LEFT", party, "RIGHT", 3, 0)
	self:CreateMarkerPanel(markers)
	local markerNames = { "Star", "Circle", "Diamond", "Triangle", "Moon", "Square", "Cross", "Skull" }
	local worldMarkerByIcon = { 5, 6, 3, 2, 7, 1, 4, 8 }
	local previousMarker
	for index, name in ipairs(markerNames) do
		local marker = CreateGroundMarkerIcon(frame, index, worldMarkerByIcon[index], name)
		if previousMarker then
			marker:SetPoint("LEFT", previousMarker, "RIGHT", 4, 0)
		else
			marker:SetPoint("TOPLEFT", 87, -7)
		end
		previousMarker = marker
	end
	local clearQuick = CreateSecureMacroButton(frame, "X", "/cwm all", "Clear all ground markers")
	clearQuick:SetSize(24, 24)
	clearQuick:SetPoint("LEFT", previousMarker, "RIGHT", 4, 0)
	local abandon = CreateFrame("Button", nil, frame, "SecureActionButtonTemplate,UIPanelButtonTemplate")
	abandon:SetSize(62, 24); abandon:SetPoint("LEFT", markers, "RIGHT", 3, 0); abandon:SetText("Abandon")
	abandon:SetAttribute("type", "macro"); abandon:SetAttribute("macrotext", "/abandon")
	abandon:SetScript("OnEnter", function(self) GameTooltip:SetOwner(self, "ANCHOR_TOP"); GameTooltip:SetText("Start Blizzard's Vote to Abandon for the active Mythic+ run."); GameTooltip:Show() end)
	abandon:SetScript("OnLeave", GameTooltip_Hide)
	self.Frame, self.Ready, self.Pull, self.Role, self.Raid, self.Party, self.Markers, self.Abandon = frame, ready, pull, role, raid, party, markers, abandon
	SlickUI.Movers:Register(frame, "groupControls", "Group Controls")
end

function GroupControls:SetEnabled(enabled)
	SlickUI.DB.groupControls.enabled = enabled == true
	self:Refresh()
end

function GroupControls:Toggle()
	if not SlickUI.DB.groupControls.enabled then
		SlickUI:Print("Enable raid / group controls in SlickUI General settings first.")
		return
	end
	SlickUI.DB.groupControls.shown = SlickUI.DB.groupControls.shown == false
	self:Refresh()
	if SlickUI.InformationBars then SlickUI.InformationBars:UpdateBlocks() end
end

function GroupControls:GetWidgetText()
	return SlickUI.DB.groupControls.shown == false and "Group: Closed" or "Group: Open"
end

function GroupControls:Initialize()
	self:CreateFrame(); self:Refresh()
	local events = CreateFrame("Frame")
	for _, event in ipairs({ "PLAYER_ENTERING_WORLD", "PLAYER_REGEN_ENABLED", "GROUP_ROSTER_UPDATE", "PARTY_LEADER_CHANGED", "CHALLENGE_MODE_START", "CHALLENGE_MODE_COMPLETED", "CHALLENGE_MODE_RESET" }) do events:RegisterEvent(event) end
	events:SetScript("OnEvent", function(_, event)
		if event == "PLAYER_REGEN_ENABLED" or not InCombatLockdown() then
			C_Timer.After(0.1, function() GroupControls:Refresh() end)
		else
			GroupControls.PendingRefresh = true
		end
	end)
	self.EventFrame = events
end

SlickUI:RegisterModule("GroupControls", GroupControls)
