local addonName = "Beef Fire Bloom"
local addonLabel = "<BeefFireBloom>"
local soundPath = "Interface\\AddOns\\BeefFireBloom\\Media\\firebloom.ogg"
local fireBloomName = "Fire Bloom"
local fallbackDuration = 20
local missingDebuffGrace = 5
local alertLockout = 24
local defaultIcon = "Interface\\Icons\\Spell_Fire_Fireball"

local frame = CreateFrame("Frame", "BeefFireBloomEventFrame")
local alertFrame = nil
local visualFrame = nil
local configFrame = nil
local moveButton = nil
local active = false
local testActive = false
local detectedAt = 0
local expiresAt = 0
local lastAlertAt = 0
local lastDebugAt = 0

local DEFAULT_DB = {
	enabled = true,
	showIcon = true,
	showTimer = true,
	playSound = true,
	sendSay = true,
	debug = false,
	locked = true,
	scale = 1,
	point = "CENTER",
	relativePoint = "CENTER",
	x = 0,
	y = 150,
}

local function BFB_Print(msg, r, g, b)
	if DEFAULT_CHAT_FRAME then
		DEFAULT_CHAT_FRAME:AddMessage(msg, r or 1, g or 0.5, b or 0)
	end
end

local function BFB_Debug(msg, force)
	if not BeefFireBloomDB or BeefFireBloomDB.debug ~= true then return end
	local now = GetTime and GetTime() or 0
	if force == true or (now - lastDebugAt) >= 1 then
		lastDebugAt = now
		BFB_Print(addonLabel .. " DEBUG: " .. msg, 0.45, 0.8, 1)
	end
end

local function BFB_FrameState(prefix)
	if not visualFrame then
		BFB_Debug(prefix .. " visualFrame=nil", true)
		return
	end
	local point, relativeTo, relativePoint, x, y = visualFrame:GetPoint(1)
	BFB_Debug(prefix .. " shown=" .. tostring(visualFrame:IsShown()) .. " alpha=" .. tostring(visualFrame:GetAlpha()) .. " point=" .. tostring(point) .. " rel=" .. tostring(relativePoint) .. " x=" .. tostring(x) .. " y=" .. tostring(y) .. " scale=" .. tostring(visualFrame:GetScale()), true)
end

local function BFB_CopyDefaults()
	local key, value
	if not BeefFireBloomDB then
		BeefFireBloomDB = {}
	end
	for key, value in pairs(DEFAULT_DB) do
		if BeefFireBloomDB[key] == nil then
			BeefFireBloomDB[key] = value
		end
	end
end

local function BFB_NormalizeScale(value)
	value = tonumber(value) or DEFAULT_DB.scale
	if value < 0.5 then value = 0.5 end
	if value > 2 then value = 2 end
	return value
end

local function BFB_ApplyAlertPosition()
	if not alertFrame then return end
	alertFrame:ClearAllPoints()
	alertFrame:SetPoint(BeefFireBloomDB.point or "CENTER", UIParent, BeefFireBloomDB.relativePoint or "CENTER", BeefFireBloomDB.x or 0, BeefFireBloomDB.y or 150)
	alertFrame:SetScale(BFB_NormalizeScale(BeefFireBloomDB.scale))
end

local function BFB_ApplyVisualPosition()
	if not visualFrame then return end
	visualFrame:ClearAllPoints()
	visualFrame:SetPoint(BeefFireBloomDB.point or "CENTER", UIParent, BeefFireBloomDB.relativePoint or "CENTER", BeefFireBloomDB.x or 0, BeefFireBloomDB.y or 150)
	visualFrame:SetScale(BFB_NormalizeScale(BeefFireBloomDB.scale))
end

local function BFB_CreateVisualFrame()
	if visualFrame then return end
	visualFrame = CreateFrame("Frame", "BeefFireBloomVisualFrame", UIParent)
	visualFrame:SetWidth(90)
	visualFrame:SetHeight(90)
	visualFrame:SetFrameStrata("FULLSCREEN_DIALOG")
	visualFrame:SetFrameLevel(120)
	visualFrame:EnableMouse(false)
	visualFrame.icon = visualFrame:CreateTexture(nil, "OVERLAY")
	visualFrame.icon:SetTexture(defaultIcon)
	visualFrame.icon:SetAllPoints(visualFrame)
	visualFrame.timerText = visualFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
	visualFrame.timerText:SetPoint("TOP", visualFrame, "BOTTOM", 0, -5)
	visualFrame.timerText:SetTextColor(1, 1, 0)
	BFB_ApplyVisualPosition()
	visualFrame:Hide()
end
local function BFB_SaveAlertPosition()
	if not alertFrame then return end
	local point, relativeTo, relativePoint, x, y = alertFrame:GetPoint(1)
	BeefFireBloomDB.point = point or "CENTER"
	BeefFireBloomDB.relativePoint = relativePoint or "CENTER"
	BeefFireBloomDB.x = x or 0
	BeefFireBloomDB.y = y or 150
end

local function BFB_UpdateMoveButton()
	if moveButton then
		if BeefFireBloomDB and BeefFireBloomDB.locked == false then
			moveButton:SetText("Lock")
		else
			moveButton:SetText("Move")
		end
	end
end

local function BFB_SetMoveMode(enabled)
	if not alertFrame then return end
	BeefFireBloomDB.locked = not enabled
	alertFrame:EnableMouse(enabled and true or false)
	BFB_UpdateMoveButton()
	if enabled then
		alertFrame:Show()
		alertFrame:SetAlpha(1)
		alertFrame.moveBg:Show()
		alertFrame.timerText:SetText("20.0")
		alertFrame:RegisterForDrag("LeftButton")
		alertFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
		alertFrame:SetScript("OnDragStop", function(self)
			self:StopMovingOrSizing()
			BFB_SaveAlertPosition()
		end)
	else
		alertFrame.moveBg:Hide()
		alertFrame:SetScript("OnDragStart", nil)
		alertFrame:SetScript("OnDragStop", nil)
		if not active then
			alertFrame:Hide()
		end
	end
end

local function BFB_CreateAlertFrame()
	if alertFrame then return end

	alertFrame = CreateFrame("Frame", "BeefFireBloomAlertFrame", UIParent)
	alertFrame:SetWidth(90)
	alertFrame:SetHeight(90)
	alertFrame:SetMovable(true)
	alertFrame:SetClampedToScreen(true)
	alertFrame:SetFrameStrata("FULLSCREEN_DIALOG")
	alertFrame:SetFrameLevel(100)
	alertFrame:EnableMouse(false)
	alertFrame:Hide()

	alertFrame.icon = alertFrame:CreateTexture(nil, "ARTWORK")
	alertFrame.icon:SetTexture(defaultIcon)
	alertFrame.icon:SetAllPoints(alertFrame)

	alertFrame.moveBg = alertFrame:CreateTexture(nil, "BACKGROUND")
	alertFrame.moveBg:SetTexture(0, 1, 0, 0.35)
	alertFrame.moveBg:SetAllPoints(alertFrame)
	alertFrame.moveBg:Hide()

	alertFrame.timerText = alertFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
	alertFrame.timerText:SetPoint("TOP", alertFrame, "BOTTOM", 0, -5)
	alertFrame.timerText:SetTextColor(1, 1, 0)

	BFB_ApplyAlertPosition()
end

local function BFB_FindFireBloom()
	local i
	for i = 1, 40 do
		local name, rank, icon, count, debuffType, duration, expirationTime = UnitDebuff("player", i)
		if name == fireBloomName then
			return true, duration, expirationTime, icon
		end
	end
	return false, nil, nil
end

local function BFB_SendSay()
	local playerName = UnitName("player") or "me"
	SendChatMessage("Fire Bloom on " .. playerName, "SAY")
end
local function BFB_ShowVisual(iconPath)
	BFB_Debug("ShowVisual start iconPath=" .. tostring(iconPath), true)
	BFB_CreateVisualFrame()
	BFB_ApplyVisualPosition()
	visualFrame.icon:SetTexture(defaultIcon)
	visualFrame:SetAlpha(1)
	visualFrame.icon:Show()
	visualFrame:Show()
	BFB_FrameState("ShowVisual after Show")
	if BeefFireBloomDB.showTimer == true then
		visualFrame.timerText:Show()
	else
		visualFrame.timerText:Hide()
	end
end


local function BFB_ForceVisualVisible()
	BFB_CreateVisualFrame()
	BFB_ApplyVisualPosition()
	visualFrame.icon:SetTexture(defaultIcon)
	visualFrame.icon:Show()
	visualFrame:Show()
end
local function BFB_ShowAlert(testMode, iconPath)
	BFB_Debug("ShowAlert testMode=" .. tostring(testMode) .. " iconPath=" .. tostring(iconPath), true)
	BFB_CreateAlertFrame()
	active = true
	testActive = testMode and true or false
	detectedAt = GetTime()
	expiresAt = detectedAt + fallbackDuration

	BFB_ShowVisual(iconPath)

	local now = GetTime()
	if testMode == true or lastAlertAt == 0 or (now - lastAlertAt) >= alertLockout then
		if not testMode then
			lastAlertAt = now
		end
		if BeefFireBloomDB.playSound == true then
			PlaySoundFile(soundPath)
		end
		if BeefFireBloomDB.sendSay == true and not testMode then
			BFB_SendSay()
		end
	end
end

local function BFB_HideAlert(force)
	BFB_FrameState("HideAlert before hide")
	active = false
	testActive = false
	if visualFrame then
		visualFrame:Hide()
	end
	if alertFrame and BeefFireBloomDB.locked == true then
		alertFrame:Hide()
	end
	frame:SetScript("OnUpdate", nil)
end

local function BFB_OnUpdate(self, elapsed)
	if not active then return end

	local now = GetTime()
	local timeLeft = expiresAt - now
	if timeLeft <= 0 then
		BFB_HideAlert()
		return
	end

	if alertFrame then
		BFB_ForceVisualVisible()
		if (now - detectedAt) > 2 then
			alertFrame:SetAlpha(0.85)
		else
			alertFrame:SetAlpha(1)
		end
		if BeefFireBloomDB.showTimer == true then
			if visualFrame then visualFrame.timerText:SetText(string.format("%.1f", timeLeft)) end
			if timeLeft < 5 then
				if visualFrame then visualFrame.timerText:SetTextColor(1, 0, 0) end
			else
				if visualFrame then visualFrame.timerText:SetTextColor(1, 1, 0) end
			end
		end
	end
end

local function BFB_CheckAura()
	if BeefFireBloomDB.enabled ~= true then return end
	local found, duration, expirationTime, iconPath = BFB_FindFireBloom()
	if found then
		BFB_Debug("CheckAura found duration=" .. tostring(duration) .. " expiration=" .. tostring(expirationTime) .. " active=" .. tostring(active), true)
		if not active then
			BFB_ShowAlert(false, iconPath)
			frame:SetScript("OnUpdate", BFB_OnUpdate)
		end
	end
end

local function BFB_SyncConfigChecks()
	if not configFrame then return end
	BeefFireBloomConfigEnabled:SetChecked(BeefFireBloomDB.enabled == true)
	BeefFireBloomConfigTimer:SetChecked(BeefFireBloomDB.showTimer == true)
	BeefFireBloomConfigSound:SetChecked(BeefFireBloomDB.playSound == true)
	BeefFireBloomConfigSay:SetChecked(BeefFireBloomDB.sendSay == true)
	BFB_UpdateMoveButton()
end

local function BFB_MakeCheck(name, parent, label, x, y, key)
	local check = CreateFrame("CheckButton", name, parent, "UICheckButtonTemplate")
	check:SetPoint("TOPLEFT", x, y)
	check:SetWidth(24)
	check:SetHeight(24)
	local text = check:CreateFontString(nil, "OVERLAY", "GameFontNormal")
	text:SetPoint("LEFT", check, "RIGHT", 4, 0)
	text:SetText(label)
	check:SetScript("OnClick", function(self)
		BeefFireBloomDB[key] = self:GetChecked() and true or false
		if key == "locked" then
			BFB_SetMoveMode(not BeefFireBloomDB.locked)
		end
		BFB_Print(addonLabel .. " " .. label .. " " .. (BeefFireBloomDB[key] and "enabled." or "disabled."))
	end)
	return check
end

local function BFB_CreateConfigFrame()
	configFrame = CreateFrame("Frame", "BeefFireBloomConfigFrame", UIParent)
	configFrame:SetWidth(330)
	configFrame:SetHeight(218)
	configFrame:SetPoint("CENTER")
	configFrame:SetFrameStrata("DIALOG")
	configFrame:SetToplevel(true)
	configFrame:EnableMouse(true)
	configFrame:SetMovable(true)
	configFrame:RegisterForDrag("LeftButton")
	configFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
	configFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
	configFrame:SetBackdrop({
		bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
		edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
		tile = true,
		tileSize = 32,
		edgeSize = 32,
		insets = { left = 11, right = 12, top = 12, bottom = 11 }
	})
	configFrame:SetBackdropColor(1, 1, 1, 1)
	configFrame:Hide()

	local title = configFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
	title:SetPoint("TOP", 0, -10)
	title:SetText(addonName)

	local close = CreateFrame("Button", nil, configFrame, "UIPanelCloseButton")
	close:SetPoint("TOPRIGHT", -6, -6)

	BFB_MakeCheck("BeefFireBloomConfigEnabled", configFrame, "Enable addon", 20, -34, "enabled")
	BFB_MakeCheck("BeefFireBloomConfigTimer", configFrame, "Show timer", 20, -62, "showTimer")

	BFB_MakeCheck("BeefFireBloomConfigSound", configFrame, "Play sound", 170, -34, "playSound")
	BFB_MakeCheck("BeefFireBloomConfigSay", configFrame, "Say warning", 170, -62, "sendSay")

	local test = CreateFrame("Button", nil, configFrame, "UIPanelButtonTemplate")
	test:SetWidth(74)
	test:SetHeight(22)
	test:SetPoint("BOTTOMLEFT", 22, 22)
	test:SetText("Test")
	test:SetScript("OnClick", function()
		BFB_ShowAlert(true)
		frame:SetScript("OnUpdate", BFB_OnUpdate)
	end)

	moveButton = CreateFrame("Button", nil, configFrame, "UIPanelButtonTemplate")
	moveButton:SetWidth(74)
	moveButton:SetHeight(22)
	moveButton:SetPoint("LEFT", test, "RIGHT", 8, 0)
	moveButton:SetScript("OnClick", function()
		BFB_CreateAlertFrame()
		BFB_SetMoveMode(BeefFireBloomDB.locked == true)
		BFB_SyncConfigChecks()
	end)
	BFB_UpdateMoveButton()

	local reset = CreateFrame("Button", nil, configFrame, "UIPanelButtonTemplate")
	reset:SetWidth(112)
	reset:SetHeight(22)
	reset:SetPoint("LEFT", moveButton, "RIGHT", 8, 0)
	reset:SetText("Reset Position")
	reset:SetScript("OnClick", function()
		BeefFireBloomDB.point = DEFAULT_DB.point
		BeefFireBloomDB.relativePoint = DEFAULT_DB.relativePoint
		BeefFireBloomDB.x = DEFAULT_DB.x
		BeefFireBloomDB.y = DEFAULT_DB.y
		BeefFireBloomDB.scale = DEFAULT_DB.scale
		BFB_ApplyAlertPosition()
		BFB_ApplyVisualPosition()
		BFB_Print(addonLabel .. ' Alert position reset.')
	end)

	local info = configFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
	info:SetPoint("TOPLEFT", 24, -126)
	info:SetWidth(280)
	info:SetJustifyH("LEFT")
	info:SetText("Use /bfb test before Kil'jaeden. Add Media\\firebloom.ogg to use the custom warning sound.")

	configFrame:SetScript("OnShow", BFB_SyncConfigChecks)
end

local function BFB_ToggleConfig()
	BFB_CopyDefaults()
	BFB_CreateAlertFrame()
	if not configFrame then
		BFB_CreateConfigFrame()
	end
	if configFrame:IsShown() then
		configFrame:Hide()
	else
		configFrame:Show()
		BFB_SyncConfigChecks()
	end
end

local function BFB_PrintHelp()
	BFB_Print(addonName .. " commands:")
	BFB_Print("/bfb - toggle config")
	BFB_Print("/bfb test - test visual, sound, and warning")
	BFB_Print("/bfb move - unlock and show alert frame")
	BFB_Print("/bfb lock - lock alert frame")
	BFB_Print("/bfb reset - reset alert position")
	BFB_Print("/bfb scale 100 - set alert scale")
	BFB_Print("/bfb sound - toggle sound")
	BFB_Print("/bfb say - toggle say warning")
	BFB_Print("/bfb debug - toggle debug messages")
end

local function BFB_HandleSlash(msg)
	local cmd, arg = string.match(msg or "", "^(%S*)%s*(.-)$")
	cmd = string.lower(cmd or "")
	BFB_CopyDefaults()
	BFB_CreateAlertFrame()

	if cmd == "" or cmd == "config" or cmd == "gui" then
		BFB_ToggleConfig()
	elseif cmd == "help" then
		BFB_PrintHelp()
	elseif cmd == "test" then
		BFB_ShowAlert(true)
		frame:SetScript("OnUpdate", BFB_OnUpdate)
	elseif cmd == "move" then
		BFB_SetMoveMode(true)
		BFB_Print(addonLabel .. " Alert unlocked. Drag it, then use /bfb lock.")
	elseif cmd == "lock" then
		BFB_SetMoveMode(false)
		BFB_Print(addonLabel .. " Alert locked.")
	elseif cmd == "reset" then
		BeefFireBloomDB.point = DEFAULT_DB.point
		BeefFireBloomDB.relativePoint = DEFAULT_DB.relativePoint
		BeefFireBloomDB.x = DEFAULT_DB.x
		BeefFireBloomDB.y = DEFAULT_DB.y
		BeefFireBloomDB.scale = DEFAULT_DB.scale
		BFB_ApplyAlertPosition()
		BFB_ApplyVisualPosition()
		BFB_Print(addonLabel .. ' Alert position reset.')
	elseif cmd == "scale" then
		local value = tonumber(arg)
		if value then
			BeefFireBloomDB.scale = BFB_NormalizeScale(value / 100)
			BFB_ApplyAlertPosition()
			BFB_ApplyVisualPosition()
			BFB_Print(addonLabel .. ' Scale set to ' .. value .. '%.')
		else
			BFB_Print("Usage: /bfb scale 100")
		end
	elseif cmd == "sound" then
		BeefFireBloomDB.playSound = not BeefFireBloomDB.playSound
		BFB_Print(addonLabel .. " Sound " .. (BeefFireBloomDB.playSound and "enabled." or "disabled."))
		BFB_SyncConfigChecks()
	elseif cmd == "say" then
		BeefFireBloomDB.sendSay = not BeefFireBloomDB.sendSay
		BFB_Print(addonLabel .. " Say warning " .. (BeefFireBloomDB.sendSay and "enabled." or "disabled."))
		BFB_SyncConfigChecks()
	elseif cmd == "debug" then
		BeefFireBloomDB.debug = not BeefFireBloomDB.debug
		BFB_Print(addonLabel .. " Debug " .. (BeefFireBloomDB.debug and "enabled." or "disabled."))
		BFB_FrameState("Debug toggle")
	else
		BFB_PrintHelp()
	end
end

SlashCmdList["BEEFFIREBLOOM"] = BFB_HandleSlash
SLASH_BEEFFIREBLOOM1 = "/bfb"
SLASH_BEEFFIREBLOOM2 = "/firebloom"
SLASH_BEEFFIREBLOOM3 = "/beeffirebloom"

frame:RegisterEvent("PLAYER_LOGIN")
frame:RegisterEvent("UNIT_AURA")
frame:RegisterEvent("PLAYER_DEAD")
frame:SetScript("OnEvent", function(self, event, arg1)
	if event == "PLAYER_LOGIN" then
		BFB_CopyDefaults()
		BFB_CreateAlertFrame()
		BFB_CreateVisualFrame()
		BFB_Print(addonLabel .. ' Loaded. Use /bfb to configure.')
	elseif event == "UNIT_AURA" then
		if arg1 == "player" then
			BFB_CheckAura()
		end
	elseif event == "PLAYER_DEAD" then
		BFB_HideAlert(true)
	end
end)

