--[[
	Cerebro - RCLootCouncil Bridge
	
	PURPOSE:
	Integrates EPGP data into RCLootCouncil's Voting Frame and handles automatic
	GP charging when items are awarded via RCLC.
	
	RESPONSIBILITIES:
	1. Inject "PR" column into RCLC Voting Frame (Officer-only view)
	2. Listen for 'RCMLAwardSuccess' messages from RCLC
	3. Charge GP for awarded items (Officer-only action)
	4. Prevent duplicate charges (Idempotency) via deterministic keys
	
	SECURITY CONTRACTS:
	
	# RBAC Enforcement
	  - Officer Validation: Checks `Cerebro:IsOfficer(Cerebro:GetFullPlayerName(sender))`
	  - No Trust: Ignores non-officer payloads completely
	  - Failure Mode: Silent ignore + debug log
	
	# Idempotency (Critical)
	  - Duplicate Awards: RCLC may fire callbacks multiple times (e.g. reload, re-announce)
	  - Dedupe Key: `sessionID|winnerFull|itemID|response|status`
	  - Persistence: Award keys stored in `db.global.rclcAwardDedupe`
	  - Atomic Commit: Key only written AFTER successful ChargeGP
	
	# Logic Rules
	  - Pass/Greed/Disenchant: Ignored (no GP charge)
	  - Test Mode: Only charges GP if `db.global.config.epgp.allowTestAwards` is strictly true
	  - Item ID: Used for dedupe key (more stable than Link string variations)
	
	EXTERNAL DEPENDENCIES:
	- RCLootCouncil (LibStub("AceAddon-3.0"):GetAddon("RCLootCouncil"))
	- Cerebro.Modules.EPGP (ChargeGP)
	- Cerebro.Database (rclcAwardDedupe)
]]--

local AddonName, PrivateTable = ...
local Cerebro = LibStub("AceAddon-3.0"):GetAddon(AddonName)
local Bridge = Cerebro:NewModule("RCLC_Bridge", "AceEvent-3.0", "AceComm-3.0")

function Bridge:OnInitialize()
	-- Wait for RCLC
	self:RegisterEvent("ADDON_LOADED", "OnAddonLoaded")
end

function Bridge:OnAddonLoaded(event, addonName)
	if addonName == "RCLootCouncil" then
		self:Enable()
		self:UnregisterEvent("ADDON_LOADED")
	end
end

function Bridge:OnEnable()
	if not C_AddOns.IsAddOnLoaded("RCLootCouncil") then return end
	
	Cerebro:Print("Bridging with RCLootCouncil...")
	
	-- Listen for RCLC messages via AceEvent (RCLC fires AceEvent messages usually)
	-- Actually RCLC uses AceEvent-3.0:SendMessage("RCMLAwardSuccess", ...)
	self:RegisterMessage("RCMLAwardSuccess", "OnRCLCAward")
	
	-- Inject GUI elements
	self:InjectOfficerColumns()
end

--[[=============================================
	Logic & RBAC
===============================================]]

-- Deterministic Key Generation
function Bridge:GetAwardKey(session, winner, itemLink, response, isTest)
	local winnerFull = Cerebro:GetFullPlayerName(winner)
	local itemID = C_Item.GetItemInfoInstant(itemLink) or 0
	local status = isTest and "TEST" or "LIVE"
	
	-- For test mode, itemID is always 0, so add timestamp to make key unique
	local uniqueSuffix = ""
	if isTest and itemID == 0 then
		uniqueSuffix = "|" .. time()
	end
	
	-- Key: session|winner|itemID|response|status[|timestamp for test]
	return string.format("%s|%s|%d|%s|%s%s",
		session or "unknown",
		winnerFull or "unknown",
		itemID,
		response or "unknown",
		status,
		uniqueSuffix
	)
end

function Bridge:OnRCLCAward(msgName, session, winner, itemLink, reason, response, type, ...)
	-- RCLC Args: session(number), winner(name), itemLink, reason(text), response(text), type(responseID), ...
	-- Note: Args might vary by RCLC version, we check availability carefully.
	
	-- Log entry point (debug only)
	Cerebro:Debug("RCLC Bridge: Received award event")
	Cerebro:Debug(string.format("  Winner: %s, Item: %s, Response: %s", tostring(winner), tostring(itemLink), tostring(response)))

	-- 1. RBAC: Only officers execute this logic
	if not Cerebro:IsOfficer() then
		Cerebro:Debug("RCLC Bridge: Ignoring award (not an officer)")
		return
	end
	
	-- 2. Validate Inputs
	if not winner or not itemLink then
		Cerebro:Debug("RCLC Bridge: Missing winner or itemLink")
		return
	end
	
	-- 3. Try to get real item link from RCLC's lootTable (works even in test mode)
	local realItemLink = itemLink
	local RCLootCouncil = LibStub("AceAddon-3.0"):GetAddon("RCLootCouncil", true)
	if RCLootCouncil then
		local RCLootCouncilML = RCLootCouncil:GetModule("RCLootCouncilML", true)
		if RCLootCouncilML and RCLootCouncilML.lootTable and RCLootCouncilML.lootTable[session] then
			local lootEntry = RCLootCouncilML.lootTable[session]
			if lootEntry.link and lootEntry.link ~= "test_mode" then
				realItemLink = lootEntry.link
				Cerebro:Debug("  Found real item link from lootTable: " .. tostring(realItemLink))
			end
		end
	end
	
	-- Update itemLink if we found the real one
	itemLink = realItemLink
	
	-- Normalize Winner
	local winnerFull = Cerebro:GetFullPlayerName(winner)
	
	-- 3. Determine Response (Prefer ID/Type if available)
	-- RCLC usually passes: response (text), type (responseID/tier)
	-- We use type (responseID) if possible, fallback to text
	local responseText = response
	
	-- 4. Check Pass/Greed/Disenchant (No GP Charge)
	-- Standard RCLC IDs: 1=Mainspec, 2=Minor, 3=Offspec, 4=Greed, 5=Pass (varies by config)
	-- Note: "Autopass" should NOT be filtered - it's a valid loot award
	local lowerResp = string.lower(responseText or "")
	local isPassResponse = (lowerResp == "pass") or 
	                       (string.find(lowerResp, "^pass$")) or
	                       (string.find(lowerResp, "greed")) or 
	                       (string.find(lowerResp, "disenchant"))
	
	-- Exclude autopass from the filter (autopass IS a valid loot award)
	if lowerResp:find("autopass") then
		isPassResponse = false
	end
	
	if isPassResponse then
		Cerebro:Debug("RCLC Bridge: Ignoring award (Reason: " .. lowerResp .. ")")
		return
	end
	
	-- 5. Test Mode Check
	local RCLootCouncilAddon = LibStub("AceAddon-3.0"):GetAddon("RCLootCouncil", true)
	local isTest = false
	if RCLootCouncilAddon and RCLootCouncilAddon.testMode then isTest = true end
	
	-- Also detect test mode from itemLink == "test_mode"
	if itemLink == "test_mode" then
		isTest = true
		Cerebro:Debug("  Detected test mode from itemLink")
	end
	
	local config = Cerebro.db.global.config.epgp
	if isTest and not config.allowTestAwards then
		Cerebro:Debug("RCLC Bridge: Ignoring Test Mode award (allowTestAwards=false)")
		return
	end

	-- 6. Idempotency Check
	local awardKey = self:GetAwardKey(session, winner, itemLink, responseText, isTest)
	if Cerebro.db.global.rclcAwardDedupe[awardKey] then
		Cerebro:Debug("RCLC Bridge: Ignoring duplicate award (Key: " .. awardKey .. ")")
		return
	end
	
	-- 7. Calculate GP (Get cost from EPGP module)
	-- Use current instance difficulty so Heroic/Mythic multipliers apply
	local _, _, difficultyID = GetInstanceInfo()
	local gp = Cerebro.modules.EPGP:GetItemGP(itemLink, difficultyID)
	
	-- Handle test mode: RCLC sends "test_mode" as itemLink, which returns 0 GP
	-- Use a default test GP value (Trinket/Weapon tier = 800)
	if isTest and (not gp or gp == 0) then
		gp = config.slotWeights["INVTYPE_TRINKET"] or 800
		Cerebro:Debug(string.format("  Using test mode default GP: %d", gp))
	end
	
	if not gp or gp == 0 then
		Cerebro:Debug("RCLC Bridge: Item has 0 GP, skipping charge.")
		return
	end
	
	-- 8. Build rich details for History
	local displayItem = itemLink
	local displaySlot
	
	if itemLink ~= "test_mode" then
		local _, _, _, equipLoc = C_Item.GetItemInfoInstant(itemLink)
		displaySlot = equipLoc and Cerebro:GetFriendlySlotName(equipLoc) or "Unknown"
	else
		-- Test mode: RCLC doesn't provide real item data
		displayItem = "[Test Item]"
		displaySlot = "Test Mode"
	end
	
	local awardDetails = {
		item = displayItem,
		slot = displaySlot,
		response = responseText,
		isTest = isTest
	}
	
	-- 9. Charge GP (Atomic Commit)
	-- ChargeGP returns true/false on success and adds preGP/postGP to details
	local success = Cerebro.modules.EPGP:ChargeGP(winnerFull, gp, "LOOT", awardDetails)
	
	if success then
		-- 10. Persist Dedupe Key
		Cerebro.db.global.rclcAwardDedupe[awardKey] = time()
		
		-- 11. Announce
		Cerebro:Print(string.format("RCLC Integration: Charged %d GP to %s for %s", 
			gp, Cerebro:ColorPlayerName(winnerFull), displayItem))
	else
		Cerebro:Debug("RCLC Bridge: Failed to charge GP (EPGP module rejected)")
	end
end

--[[=============================================
	GUI Injection (Officer)
===============================================]]

function Bridge:InjectOfficerColumns()
	local RCLootCouncil = LibStub("AceAddon-3.0"):GetAddon("RCLootCouncil", true)
	if not RCLootCouncil then return end
	
	local RCVotingFrame = RCLootCouncil:GetModule("RCVotingFrame", true)
	if not RCVotingFrame then return end
	
	-- Check for existing
	for _, col in ipairs(RCVotingFrame.scrollCols or {}) do
		if col.colName == "pr" then return end
	end
	
	local function SetCellPR(rowFrame, frame, data, cols, row, realrow, column, fShow, table, ...)
		local name = data[realrow].name
		local player = Cerebro.Player:New(name)
		local pr = player:GetPR() or 0
		
		frame.text:SetText(string.format("%.2f", pr))
		frame.text:SetTextColor(1, 0.82, 0, 1) -- Gold
		
		data[realrow].cols[column].value = pr
	end
	
	local prColumn = {
		name = "PR",
		DoCellUpdate = SetCellPR,
		colName = "pr",
		width = 45,
		align = "CENTER",
		defaultsort = "dsc",
		sort = function(table, rowa, rowb, sortby)
			local v1 = table[rowa].cols[sortby].value
			local v2 = table[rowb].cols[sortby].value
			return v1 < v2 -- Ascending? strict logic depends on RCLC implementation. Usually returning true means a < b.
		end,
	}
	
	-- Insert at position 5 (After Role/Class usually)
	-- Verify scrollCols exists
	if RCVotingFrame.scrollCols then
		table.insert(RCVotingFrame.scrollCols, 5, prColumn)
		Cerebro:Debug("Injected PR column into RCLC.")
	end
end

--[[=============================================
	GUI Injection (Candidate)
===============================================]]

function Bridge:InjectCandidateLabel()
	-- Hook RCLootFrame (The window candidates see)
	local RCLootFrame = RCLootCouncil_LootFrame -- Global name often used
	
	if not RCLootFrame and _G["RCLootFrame"] then
		RCLootFrame = _G["RCLootFrame"]
	end
	
	if not RCLootFrame then
		-- RCLC frame not found yet. It's usually created on demand.
		-- We can try to hook AceAddon:Enable/OnEnable for RCLC or just do a lazy init
		-- For now, just return. The Timer check or OnShow hook elsewhere might be better.
		return 
	end
	
	-- Assuming we found the frame or can attach to it.
	-- For safety, let's create a standalone frame that anchors to it whenever it's shown.
	-- Or simpler: Add an "Overlay" frame.
	
	if not self.prLabelFrame then
		local f = CreateFrame("Frame", "CerebroPRLabel", UIParent)
		f:SetFrameStrata("DIALOG")
		f:SetSize(100, 20)
		
		local t = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
		t:SetPoint("CENTER")
		t:SetText("PR: ---")
		f.text = t
		
		self.prLabelFrame = f
		f:Hide()
		
		-- Simple update script to show/hide with RCLC
		f:SetScript("OnUpdate", function(self, elapsed)
			-- Try to find frame if we lost it or it wasn't there
			if not RCLootFrame and _G["RCLootFrame"] then
				RCLootFrame = _G["RCLootFrame"]
			end

			if RCLootFrame and RCLootFrame:IsVisible() then
				self:Show()
				self:ClearAllPoints()
				self:SetPoint("TOPRIGHT", RCLootFrame, "TOPRIGHT", -25, -50)
				
				local p = Cerebro.Player:New("player")
				self.text:SetText(string.format("Your PR: %.2f", p:GetPR()))
			else
				self:Hide()
			end
		end)
	end
end

return Bridge
