local addonName = ...
local AtlasLoot = _G.AtlasLoot
if not AtlasLoot or not AtlasLoot.ItemDB or not AtlasLoot.GUI then
	return
end

local AL = AtlasLoot.Locales
local GetAlTooltip = AtlasLoot.Tooltip and AtlasLoot.Tooltip.GetTooltip

local SPEC_TO_CONTENT = {
	Aff = "WarlockAffliction",
	Dest = "WarlockDestruction",
	Arc = "MageArcane",
	Fire = "MageFire",
	BM = "HunterBM",
	SV = "HunterSV",
	Bear = "DruidBear",
	Cat = "DruidCat",
	Owl = "DruidBalance",
	Tree = "DruidRestoration",
	Resto = "ShamanRestoration",
	Ele = "ShamanElemental",
	Enh = "ShamanEnhancement",
	Shad = "PriestShadow",
	Holy = "PriestHoly",
	Rog = "RogueDPS",
	Arms = "WarriorArms",
	Fury = "WarriorFury",
	Prot = "WarriorProt",
	Ret = "PaladinRet",
	Heal = "PaladinHeal",
	Tank = "PaladinTank",
}

local SLOT_KEYS = {
	"Head",
	"Neck",
	"Shoulders",
	"Back",
	"Chest",
	"Wrist",
	"Hands",
	"Waist",
	"Legs",
	"Feet",
	"Ring",
	"Trinket",
	"Main Hand",
	"Off Hand",
	"One Hand",
	"Two Hand",
	"Ranged",
}

local SLOT_LABEL_TO_KEY = {}
for i = 1, #SLOT_KEYS do
	local slotKey = SLOT_KEYS[i]
	SLOT_LABEL_TO_KEY[slotKey] = slotKey
	SLOT_LABEL_TO_KEY[AL[slotKey] or slotKey] = slotKey
end

local scoreMap = nil

local function getBisDB()
	_G.Unforvegan_BISDB = _G.Unforvegan_BISDB or {}
	if _G.Unforvegan_BISDB.hitCapped == nil then
		_G.Unforvegan_BISDB.hitCapped = false
	end
	return _G.Unforvegan_BISDB
end

local function isHitCapped()
	return getBisDB().hitCapped and true or false
end

local function getBaselineEntry(spec, slotKey)
	local baseline = _G.Unforvegan_BiSData and _G.Unforvegan_BiSData.baseline
	if not baseline or not spec or not slotKey then
		return nil
	end
	return baseline[spec .. ":" .. slotKey]
end

local function addScore(map, contentName, slotKey, phase, itemID, normalScore, hitScore)
	if not map[contentName] then
		map[contentName] = {}
	end
	if not map[contentName][slotKey] then
		map[contentName][slotKey] = {}
	end
	if not map[contentName][slotKey][phase] then
		map[contentName][slotKey][phase] = {}
	end

	local existing = map[contentName][slotKey][phase][itemID]
	if not existing then
		map[contentName][slotKey][phase][itemID] = { n = normalScore, h = hitScore }
		return
	end

	if normalScore and ((not existing.n) or normalScore > existing.n) then
		existing.n = normalScore
	end
	if hitScore and ((not existing.h) or hitScore > existing.h) then
		existing.h = hitScore
	end
end

local function buildScoreMap()
	local bisData = _G.Unforvegan_BiSData and _G.Unforvegan_BiSData.byItem
	if type(bisData) ~= "table" then
		return nil
	end

	local map = {}
	for rawItemID, rows in pairs(bisData) do
		local itemID = tonumber(rawItemID)
		if itemID and type(rows) == "table" then
			for i = 1, #rows do
				local row = rows[i]
				local contentName = SPEC_TO_CONTENT[row.s]
				local slotKey = row.sl
				local phase = tonumber(row.p)
				if contentName and slotKey and phase and phase >= 1 and phase <= 5 then
					local baseline = getBaselineEntry(row.s, slotKey)
					local normalNum = tonumber(row.e)
					local normalDen = baseline and baseline.m and tonumber(baseline.m[phase]) or nil
					local hitNum = tonumber(row.h)
					local hitDen = baseline and baseline.mh and tonumber(baseline.mh[phase]) or nil

					local normalScore = (normalNum and normalDen and normalDen > 0) and ((normalNum / normalDen) * 100) or nil
					local hitScore = (hitNum and hitDen and hitDen > 0) and ((hitNum / hitDen) * 100) or nil

					addScore(map, contentName, slotKey, phase, itemID, normalScore, hitScore)
				end
			end
		end
	end

	return map
end

local function ensureScoreMap()
	if scoreMap then
		return true
	end
	scoreMap = buildScoreMap()
	return scoreMap ~= nil
end

local function getPhaseFromDifficulty(diffData, dif)
	local phaseFromUName = diffData and diffData.uniqueName and tostring(diffData.uniqueName):match("^p(%d+)$")
	if phaseFromUName then
		return tonumber(phaseFromUName)
	end
	if diffData and diffData.difficultyID and diffData.difficultyID >= 1 and diffData.difficultyID <= 5 then
		return diffData.difficultyID
	end
	if type(dif) == "number" and dif >= 1 and dif <= 5 then
		return dif
	end
	return nil
end

local function getSlotKey(addonKey, contentName, bossID)
	local bossData = AtlasLoot.ItemDB:GetBossTable(addonKey, contentName, bossID)
	if not bossData then
		return nil
	end
	return SLOT_LABEL_TO_KEY[bossData.name]
end

local function getScore(contentName, slotKey, phase, itemID, hitMode)
	if not ensureScoreMap() then
		return nil
	end
	local slotMap = scoreMap[contentName] and scoreMap[contentName][slotKey]
	local phaseMap = slotMap and slotMap[phase]
	local itemScores = phaseMap and phaseMap[itemID]
	if not itemScores then
		return nil
	end
	return hitMode and itemScores.h or itemScores.n
end

local function sortedItemsForMode(items, contentName, slotKey, phase, hitMode)
	local rows = {}
	for i = 1, #items do
		local row = items[i]
		local itemID = row and row[2]
		local score = (type(itemID) == "number") and getScore(contentName, slotKey, phase, itemID, hitMode) or nil
		rows[#rows + 1] = {
			row = row,
			score = score,
			originalIndex = i,
		}
	end

	table.sort(rows, function(a, b)
		local aScore = a.score
		local bScore = b.score
		if aScore ~= nil and bScore ~= nil then
			if aScore ~= bScore then
				return aScore > bScore
			end
		elseif aScore ~= nil then
			return true
		elseif bScore ~= nil then
			return false
		end
		return a.originalIndex < b.originalIndex
	end)

	local sorted = {}
	for k, v in pairs(items) do
		if type(k) ~= "number" then
			sorted[k] = v
		end
	end

	local IT_AMOUNT1 = _G.ATLASLOOT_IT_AMOUNT1 or 903

	for i = 1, #rows do
		local oldRow = rows[i].row
		if type(oldRow) ~= "table" then
			return items
		end
		local newRow = {}
		for k, v in pairs(oldRow) do
			newRow[k] = v
		end
		newRow[1] = i
		local score = rows[i].score
		if score then
			newRow[IT_AMOUNT1] = math.floor(score + 0.5) .. "%"
		else
			newRow[IT_AMOUNT1] = nil
		end
		sorted[i] = newRow
	end

	return sorted
end

if not AtlasLoot.ItemDB.__tbcaBisSortWrapped then
	local originalGetItemTable = AtlasLoot.ItemDB.GetItemTable
	AtlasLoot.ItemDB.GetItemTable = function(self, addonKey, contentName, bossID, dif)
		local items, tableType, diffData = originalGetItemTable(self, addonKey, contentName, bossID, dif)
		if addonKey ~= addonName or type(items) ~= "table" then
			return items, tableType, diffData
		end

		local phase = getPhaseFromDifficulty(diffData, dif)
		local slotKey = getSlotKey(addonKey, contentName, bossID)
		if not phase or not slotKey then
			return items, tableType, diffData
		end

		local sorted = sortedItemsForMode(items, contentName, slotKey, phase, isHitCapped())
		return sorted or items, tableType, diffData
	end
	AtlasLoot.ItemDB.__tbcaBisSortWrapped = true
end

local function isTbcaBisModuleSelected()
	local selected = AtlasLoot.db and AtlasLoot.db.GUI and AtlasLoot.db.GUI.selected
	return selected and selected[1] == addonName
end

local function getHitStatusLabel()
	return isHitCapped() and "ON" or "OFF"
end

local function refreshHitTitle()
	local frame = AtlasLoot.GUI and AtlasLoot.GUI.frame and AtlasLoot.GUI.frame.contentFrame
	local title = frame and frame.title
	if not title then
		return
	end

	local text = title:GetText() or ""
	text = text:gsub(" %|cffffcc00%[I am hit%-capped: [A-Z]+%]%|r$", "")
	if isTbcaBisModuleSelected() then
		text = text .. " |cffffcc00[I am hit-capped: " .. getHitStatusLabel() .. "]|r"
	end
	title:SetText(text)
end

local function refreshHitToggleButton()
	local frame = AtlasLoot.GUI and AtlasLoot.GUI.frame and AtlasLoot.GUI.frame.contentFrame
	local button = frame and frame.tbcaBisHitToggle
	if not button then
		return
	end

	if isTbcaBisModuleSelected() then
		button:SetText("Hit-capped: " .. getHitStatusLabel())
		button:Show()
	else
		button:Hide()
	end
end

local function onHitToggleClick()
	local db = getBisDB()
	db.hitCapped = not db.hitCapped
	refreshHitToggleButton()
	if AtlasLoot.GUI and AtlasLoot.GUI.ItemFrame then
		AtlasLoot.GUI.ItemFrame:Refresh(true)
	end
	refreshHitTitle()
end

local function onHitToggleEnter(self)
	if not GetAlTooltip then
		return
	end
	local tooltip = GetAlTooltip()
	if not tooltip then
		return
	end
	tooltip:ClearLines()
	tooltip:SetOwner(self, "ANCHOR_RIGHT", -(self:GetWidth() * 0.5), 5)
	tooltip:AddLine("TBCA_BIS I am hit-capped")
	tooltip:AddLine("Current: " .. getHitStatusLabel(), 1, 1, 1)
	tooltip:AddLine("Use ON when you already have enough hit from other gear.", 0.8, 0.8, 0.8)
	tooltip:AddLine("Items with extra hit can score lower in this mode.", 0.8, 0.8, 0.8)
	tooltip:Show()
end

local function onHitToggleLeave()
	if GetAlTooltip then
		GetAlTooltip():Hide()
	end
end

local function createHitToggleButton()
	local gui = AtlasLoot.GUI
	if not gui or not gui.frame or not gui.frame.contentFrame then
		return
	end

	local contentFrame = gui.frame.contentFrame
	if contentFrame.tbcaBisHitToggle then
		return
	end

	local button = gui.CreateButton()
	button:SetParent(contentFrame)
	button:SetPoint("RIGHT", contentFrame.nextPageButton, "LEFT", -5, 0)
	button:SetScript("OnClick", onHitToggleClick)
	button:SetScript("OnEnter", onHitToggleEnter)
	button:SetScript("OnLeave", onHitToggleLeave)

	contentFrame.tbcaBisHitToggle = button
	refreshHitToggleButton()
end

if type(AtlasLoot.GUI.CreateFrame) == "function" then
	hooksecurefunc(AtlasLoot.GUI, "CreateFrame", function()
		createHitToggleButton()
		refreshHitToggleButton()
		refreshHitTitle()
	end)
end

-- ============================================================
-- BiS Phase indicator in the main title bar
-- Shows "Phase: X" and clicking opens the TBCA_BIS options panel
-- ============================================================
local function updateBisPhaseLabel()
	local frame = AtlasLoot.GUI and AtlasLoot.GUI.frame
	if not frame or not frame.titleFrame or not frame.titleFrame.tbcaBisPhase then return end
	local phase = _G.Unforvegan_BISDB and _G.Unforvegan_BISDB.maxPhase or 1
	frame.titleFrame.tbcaBisPhase.label:SetText("|cFF55AAFF[BiS Phase: " .. phase .. "  ▸]|r")
end

local function injectBisPhaseButton()
	local frame = AtlasLoot.GUI and AtlasLoot.GUI.frame
	if not frame or not frame.titleFrame then return end
	if frame.titleFrame.tbcaBisPhase then return end

	local btn = CreateFrame("Button", nil, frame.titleFrame)
	btn:SetSize(110, 14)
	btn:SetPoint("LEFT", frame.titleFrame, "CENTER", 80, 0)

	local lbl = btn:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
	lbl:SetAllPoints(btn)
	lbl:SetJustifyH("LEFT")
	btn.label = lbl

	btn:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
	btn:GetHighlightTexture():SetVertexColor(0.3, 0.6, 1.0)

	btn:SetScript("OnClick", function()
		if _G.TBCA_BIS_OpenOptions then
			_G.TBCA_BIS_OpenOptions()
		elseif SlashCmdList and SlashCmdList.BIS then
			SlashCmdList.BIS("")
		end
	end)
	btn:SetScript("OnEnter", function(self)
		GameTooltip:SetOwner(self, "ANCHOR_BOTTOM")
		GameTooltip:SetText("BiS Phase Setting", 1, 1, 1)
		GameTooltip:AddLine("Click to open TBCA_BIS options.", 0.8, 0.8, 0.8, true)
		GameTooltip:Show()
	end)
	btn:SetScript("OnLeave", function() GameTooltip:Hide() end)

	frame.titleFrame.tbcaBisPhase = btn
	updateBisPhaseLabel()
end

if type(AtlasLoot.GUI.Create) == "function" then
	hooksecurefunc(AtlasLoot.GUI, "Create", function()
		injectBisPhaseButton()
	end)
end

if AtlasLoot.GUI.frame and AtlasLoot.GUI.frame.titleFrame then
	injectBisPhaseButton()
end

if AtlasLoot.GUI.ItemFrame and type(AtlasLoot.GUI.ItemFrame.Refresh) == "function" then
	hooksecurefunc(AtlasLoot.GUI.ItemFrame, "Refresh", function()
		refreshHitToggleButton()
		refreshHitTitle()
		updateBisPhaseLabel()
	end)
end

if AtlasLoot.GUI.frame and AtlasLoot.GUI.frame.contentFrame then
	createHitToggleButton()
	refreshHitToggleButton()
	refreshHitTitle()
	if AtlasLoot.GUI.ItemFrame.frame and AtlasLoot.GUI.ItemFrame.frame.Refresh then
		hooksecurefunc(AtlasLoot.GUI.ItemFrame.frame, "Refresh", function()
			refreshHitToggleButton()
			refreshHitTitle()
			updateBisPhaseLabel()
		end)
	end
end
