local _, addon = ...
local HLY = addon.HLY

local C_Item = C_Item
local C_Timer = C_Timer
local ConfirmLootRoll = ConfirmLootRoll
local CreateFrame = CreateFrame
local Enum = Enum
local GetLootRollItemInfo = GetLootRollItemInfo
local GetLootRollItemLink = GetLootRollItemLink
local IsInInstance = IsInInstance
local RollOnLoot = RollOnLoot
local StaticPopup_OnClick = StaticPopup_OnClick
local StaticPopup_Hide = StaticPopup_Hide
local _G = _G
local time = time

local lootFrame = CreateFrame("Frame")
local HOUSING_CLASS_ID = (Enum and Enum.ItemClass and Enum.ItemClass.Housing) or 20
local ROLL_PASS = 0
local ROLL_NEED = 1
local ROLL_GREED = 2
local pendingLootConfirms = {}
local pendingBindConfirms = {}
local pendingBindRollTypes = {}
local pendingStaticPopupConfirms = {}
local STATIC_POPUP_CONFIRM_WINDOW = 8
local STATIC_POPUP_MAX_INDEX = 4

local function IsInstanceLoot()
    if not IsInInstance then
        return false
    end

    local inInstance, instanceType = IsInInstance()
    return inInstance and (instanceType == "party" or instanceType == "raid")
end

local function IsHouseDecorItem(itemLink)
    if not itemLink or not C_Item or not C_Item.GetItemInfoInstant then
        return false
    end

    local _, _, _, _, _, itemClassID = C_Item.GetItemInfoInstant(itemLink)
    return itemClassID == HOUSING_CLASS_ID
end

local function GetItemNameFromLink(itemLink)
    if type(itemLink) ~= "string" then
        return nil
    end

    return itemLink:match("%[(.-)%]")
end

local function GetDecorRollType(action, canNeed, canGreed)
    if action == "pass" then
        return ROLL_PASS
    end

    if action == "need" and canNeed then
        return ROLL_NEED
    end

    if canGreed then
        return ROLL_GREED
    end

    return ROLL_PASS
end

function HLY:HandleLootRoll(rollID)
    local db = self.db and self.db.loot
    if not db or not db.enabled or not rollID or not RollOnLoot or not GetLootRollItemInfo or not IsInstanceLoot() then
        return
    end

    local itemLink = GetLootRollItemLink and GetLootRollItemLink(rollID)
    if not IsHouseDecorItem(itemLink) then
        return
    end

    local _, _, _, _, _, canNeed, canGreed = GetLootRollItemInfo(rollID)
    local rollType = GetDecorRollType(db.decorAction, canNeed, canGreed)

    if rollType ~= ROLL_PASS and ConfirmLootRoll then
        pendingLootConfirms[rollID] = rollType
        pendingBindConfirms[rollID] = time() + STATIC_POPUP_CONFIRM_WINDOW
        pendingBindRollTypes[rollID] = rollType
    end

    if rollType ~= ROLL_PASS then
        local itemName = GetItemNameFromLink(itemLink)
        if itemName then
            pendingStaticPopupConfirms[itemName] = time() + STATIC_POPUP_CONFIRM_WINDOW
            if C_Timer then
                C_Timer.After(0.15, function()
                    self:ConfirmPendingLootStaticPopup()
                end)
                C_Timer.After(0.5, function()
                    self:ConfirmPendingLootStaticPopup()
                end)
                C_Timer.After(1.0, function()
                    self:ConfirmPendingLootStaticPopup()
                end)
                C_Timer.After(2.0, function()
                    self:ConfirmPendingLootStaticPopup()
                end)
            end
        end
    end

    if C_Timer then
        C_Timer.After(0.05, function()
            RollOnLoot(rollID, rollType)
        end)
        return
    end

    RollOnLoot(rollID, rollType)
end

function HLY:HandleLootRollConfirm(rollID, rollType)
    if not rollID or not ConfirmLootRoll or pendingLootConfirms[rollID] ~= rollType then
        return
    end

    pendingLootConfirms[rollID] = nil
    pendingBindConfirms[rollID] = nil
    pendingBindRollTypes[rollID] = nil
    ConfirmLootRoll(rollID, rollType)
end

function HLY:HandleLootBindConfirm(rollID)
    if not rollID or not ConfirmLootRoll or not pendingBindConfirms[rollID] then
        return
    end

    local rollType = pendingBindRollTypes[rollID] or ROLL_GREED
    pendingLootConfirms[rollID] = nil
    pendingBindConfirms[rollID] = nil
    pendingBindRollTypes[rollID] = nil
    ConfirmLootRoll(rollID, rollType)
end

local function GetStaticPopupText(popup, index)
    local textRegion = (popup and (popup.text or popup.Text)) or _G["StaticPopup" .. index .. "Text"]
    return textRegion and textRegion.GetText and textRegion:GetText() or nil
end

local function ClickStaticPopupOkay(popup, index)
    local button = (popup and (popup.button1 or popup.Button1)) or _G["StaticPopup" .. index .. "Button1"]
    if button and button.Click then
        button:Click()
        return true
    end

    if StaticPopup_OnClick and popup then
        StaticPopup_OnClick(popup, 1)
        return true
    end

    return false
end

function HLY:ConfirmPendingLootStaticPopup()
    if not StaticPopup_OnClick then
        return
    end

    local now = time()
    for itemName, expiresAt in pairs(pendingStaticPopupConfirms) do
        if expiresAt <= now then
            pendingStaticPopupConfirms[itemName] = nil
        end
    end

    for rollID, expiresAt in pairs(pendingBindConfirms) do
        if expiresAt <= now then
            pendingBindConfirms[rollID] = nil
            pendingBindRollTypes[rollID] = nil
        end
    end

    for index = 1, STATIC_POPUP_MAX_INDEX do
        local popup = _G["StaticPopup" .. index]
        local text = GetStaticPopupText(popup, index)
        if popup and popup:IsShown() and type(text) == "string" then
            for itemName in pairs(pendingStaticPopupConfirms) do
                if text:find(itemName, 1, true) then
                    pendingStaticPopupConfirms[itemName] = nil
                    ClickStaticPopupOkay(popup, index)
                    if StaticPopup_Hide and popup.which then
                        StaticPopup_Hide(popup.which)
                    end
                    return
                end
            end
        end
    end
end

function HLY:SetupLoot()
    if self.lootSetup then
        return
    end

    lootFrame:RegisterEvent("START_LOOT_ROLL")
    lootFrame:RegisterEvent("CONFIRM_LOOT_ROLL")
    lootFrame:RegisterEvent("LOOT_BIND_CONFIRM")
    lootFrame:SetScript("OnEvent", function(_, event, rollID, rollType)
        if event == "START_LOOT_ROLL" then
            self:HandleLootRoll(rollID)
        elseif event == "CONFIRM_LOOT_ROLL" then
            self:HandleLootRollConfirm(rollID, rollType)
        elseif event == "LOOT_BIND_CONFIRM" then
            self:HandleLootBindConfirm(rollID)
        end
    end)

    self.lootSetup = true
end
