local DR = select(2, ...)

--- Group loot funneling: when enabled (default), everyone auto-passes the
--- Blizzard group-loot roll and the raid leader auto-needs it, so items land
--- in the leader's bags and get distributed through DetentionRolls sessions
--- and the deferred-trade queue.
---
--- Safety: raiders only auto-pass when the group leader is confirmed to be
--- running DetentionRolls (via version announce). If the leader has no addon,
--- normal Blizzard rolls proceed untouched.
local GroupLoot = {
  autoRolled = {},
}
LibStub("AceEvent-3.0"):Embed(GroupLoot)

-- Untradeable drops that must not be funneled to the leader (they'd be stuck).
local IGNORED_ITEMS = {
  [209035] = true, -- Hearthstone of the Flame (Amirdrassil)
  [236687] = true, -- Explosive Hearthstone (Liberation of Undermine)
  [246565] = true, -- Cosmic Hearthstone (Manaforge Omega)
  [250104] = true, -- Soulbinder's Nethermantle
  [264672] = true, -- Cosmic Ritual Stone (Voidspire toy)
  [264313] = true, -- Madcap Redcap (Sporefall toy)
  [264367] = true, -- Mycomancer's Hearthspore (Sporefall HS)
  [268280] = true, -- Sporelord's Shroom Cap (Sporefall cosmetic)
}

local ROLL_PASS = 0
local ROLL_NEED = 1
local ROLL_GREED = 2
local ROLL_TRANSMOG = 4

--- Pure decision: should this item be handled at all?
function GroupLoot:ShouldHandleItem(itemId, quality)
  if itemId and IGNORED_ITEMS[itemId] then
    return false
  end
  -- Never touch legendary-or-better drops.
  local legendary = (Enum and Enum.ItemQuality and Enum.ItemQuality.Legendary) or 5
  if (quality or 0) >= legendary then
    return false
  end
  return true
end

--- Pure decision: what to roll. The leader needs everything it can; raiders
--- pass on everything.
function GroupLoot:DecideRoll(isLeader, canNeed, canTransmog, canGreed)
  if not isLeader then
    return ROLL_PASS
  end
  if canNeed then
    return ROLL_NEED
  end
  if canTransmog then
    return ROLL_TRANSMOG
  end
  if canGreed then
    return ROLL_GREED
  end
  return ROLL_PASS
end

local function findLeaderGuid()
  if UnitIsGroupLeader("player") then
    return UnitGUID("player")
  end
  if IsInRaid() then
    for i = 1, (GetNumGroupMembers() or 0) do
      local unit = "raid" .. i
      if UnitExists(unit) and UnitIsGroupLeader(unit) then
        return UnitGUID(unit)
      end
    end
  elseif IsInGroup() then
    for i = 1, 4 do
      local unit = "party" .. i
      if UnitExists(unit) and UnitIsGroupLeader(unit) then
        return UnitGUID(unit)
      end
    end
  end
  return nil
end

function GroupLoot:IsFunnelActive()
  if not DR.db.profile.autoPassEnabled then
    return false
  end
  -- Each client checks its own raid-activation flag (set by the leader's
  -- prompt and broadcast to the raid). No designated raid = normal rolls.
  if not DR:Require("Modules.RaidActivation"):IsActive() then
    return false
  end
  if not IsInGroup() then
    return false
  end
  if UnitIsGroupLeader("player") then
    return true
  end

  local guid = findLeaderGuid()
  if not guid then
    return false
  end
  local peers = DR:Require("Modules.VersionCheck").peers or {}
  return peers[guid] ~= nil
end

function GroupLoot:HideGroupLootFrameWithRollID(rollID)
  local container = rawget(_G, "GroupLootContainer")
  local removeFrame = rawget(_G, "GroupLootContainer_RemoveFrame")
  if not container or not removeFrame then
    return
  end
  for i = 1, 4 do
    local frame = rawget(_G, "GroupLootFrame" .. i)
    if frame and frame:IsShown() and frame.rollID == rollID then
      removeFrame(container, frame)
    end
  end
end

function GroupLoot:OnStartLootRoll(rollID)
  if not rollID or not self:IsFunnelActive() then
    return
  end
  if not (GetLootRollItemLink and GetLootRollItemInfo and RollOnLoot) then
    return
  end

  local link = GetLootRollItemLink(rollID)
  if not link then
    return
  end

  local _, _, _, quality, _, canNeed, canGreed, _, _, _, _, _, canTransmog = GetLootRollItemInfo(rollID)
  local itemId = nil
  if C_Item and C_Item.GetItemInfoInstant then
    local ok, id = pcall(C_Item.GetItemInfoInstant, link)
    if ok then
      itemId = id
    end
  end

  if not self:ShouldHandleItem(itemId, quality) then
    return
  end

  local isLeader = UnitIsGroupLeader("player") == true
  local rollType = self:DecideRoll(isLeader, canNeed, canTransmog, canGreed)
  self.autoRolled[rollID] = rollType

  -- Slight delay so other addons touching the loot frames finish first.
  DR:ScheduleTimer(function()
    RollOnLoot(rollID, rollType)
    self:HideGroupLootFrameWithRollID(rollID)
  end, 0.05)

  if isLeader and rollType ~= ROLL_PASS then
    DR:Print("Auto-needed for distribution: " .. link)
  end

  DR:Require("Services.Audit"):Append("GROUP_LOOT_AUTO_ROLL", {
    rollID = rollID,
    rollType = rollType,
    itemLink = link,
    isLeader = isLeader,
  })
end

function GroupLoot:OnConfirmLootRoll(rollID, rollType)
  -- Auto-confirm the BoP prompt, but only for rolls we initiated ourselves.
  if self.autoRolled[rollID] == rollType and ConfirmLootRoll then
    ConfirmLootRoll(rollID, rollType)
  end
end

function GroupLoot:OnInitialize()
  self.autoRolled = {}

  self:RegisterEvent("START_LOOT_ROLL", function(_, rollID)
    self:OnStartLootRoll(rollID)
  end)
  self:RegisterEvent("CONFIRM_LOOT_ROLL", function(_, rollID, rollType)
    self:OnConfirmLootRoll(rollID, rollType)
  end)
  self:RegisterEvent("CANCEL_LOOT_ROLL", function(_, rollID)
    self.autoRolled[rollID] = nil
  end)
end

DR:RegisterModule("Modules.GroupLoot", GroupLoot)
