local _, ns = ...

local eventFrame = CreateFrame("Frame")
ns.eventFrame = eventFrame

local function parseLootMessage(msg)
    if not msg or msg == "" then return nil end
    local itemLink = msg:match("(|c%x+|Hitem:.-|h%[.-%]|h|r)")
    if itemLink and itemLink ~= "" then return itemLink end
    local bracketName = msg:match("%[(.-)%]")
    if bracketName and bracketName ~= "" then return bracketName end
    return nil
end

local function recordLootFromWindow()
    if not GetNumLootItems then return false end
    if ns.Fishing:HasRecordedCatchThisWindow() then return false end

    local primaryItem = nil
    for slot = 1, GetNumLootItems() do
        local itemLink = GetLootSlotLink and GetLootSlotLink(slot) or nil
        if not itemLink or itemLink == "" then
            local itemName = GetLootSlotInfo and select(2, GetLootSlotInfo(slot)) or nil
            itemLink = itemName
        end
        if itemLink and itemLink ~= "" then
            primaryItem = itemLink
            break
        end
    end

    if primaryItem and ns.Tracking:RecordCatch(primaryItem) then
        ns.Alerts:PlayBiteAlert()
        ns.Fishing:MarkCatchRecorded(0.5)
        if ns.Fishing:IsFishing() then ns.Fishing:ClearBindings() end
        return true
    end
    return false
end

eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("ZONE_CHANGED")
eventFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
eventFrame:RegisterEvent("SKILL_LINES_CHANGED")
eventFrame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
eventFrame:RegisterEvent("UNIT_INVENTORY_CHANGED")
eventFrame:RegisterEvent("CHAT_MSG_LOOT")
eventFrame:RegisterEvent("LOOT_OPENED")
eventFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
eventFrame:RegisterEvent("GLOBAL_MOUSE_DOWN")
eventFrame:RegisterEvent("GLOBAL_MOUSE_UP")
eventFrame:RegisterEvent("UNIT_AURA")

local function handleEvent(event, ...)
    if event == "PLAYER_LOGIN" then ns.Core:Startup() return end
    if not ns.state.initialized then return end

    if event == "ZONE_CHANGED" or event == "ZONE_CHANGED_NEW_AREA" or event == "SKILL_LINES_CHANGED" then
        ns.Tracking:RefreshAll()
        if ns.Nearby and ns.Nearby.OnZoneChanged then ns.Nearby:OnZoneChanged() end
        -- Lure reminder on zone change
        if (event == "ZONE_CHANGED" or event == "ZONE_CHANGED_NEW_AREA")
            and ns.DB and ns.DB.profile.alerts.lureReminderOnZoneChange
            and ns.Fishing:HasLureTarget() then
            local lureState = ns.Fishing:GetLureState()
            if not lureState.active then
                ns:ScheduleTimer(function()
                    if ns.DB.profile.alerts.lureReminderOnZoneChange then
                        ns.Utils:Print("|cffffcc00Reminder:|r Apply your lure before the first cast in this zone.")
                    end
                end, 2.5)
            end
        end
        return
    end
    if event == "PLAYER_EQUIPMENT_CHANGED" then
        ns.Tracking:RefreshAll()
        ns.Fishing:CheckSleepForMissingTool()
        return
    end
    if event == "UNIT_INVENTORY_CHANGED" then
        local unit = ...
        if unit == "player" then ns.Tracking:RefreshAll() end
        return
    end
    if event == "UNIT_SPELLCAST_SUCCEEDED" then
        ns.Fishing:HandleSpellcast(...)
        return
    end
    if event == "LOOT_OPENED" then
        if ns.Fishing:IsAwaitingFishingLoot() or ns.Fishing:IsFishing() then
            recordLootFromWindow()
        end
        return
    end
    if event == "CHAT_MSG_LOOT" then
        local itemLink = parseLootMessage(...)
        if itemLink and (ns.Fishing:IsAwaitingFishingLoot() or ns.Fishing:IsFishing()) and not ns.Fishing:HasRecordedCatchThisWindow() then
            if ns.Tracking:RecordCatch(itemLink) then
                ns.Alerts:PlayBiteAlert()
                ns.Fishing:MarkCatchRecorded(0.25)
                if ns.Fishing:IsFishing() then ns.Fishing:ClearBindings() end
            end
        end
        return
    end
    if event == "PLAYER_REGEN_ENABLED" then
        if ns.state.pendingClear then
            ns.state.pendingClear = false
            ns.Fishing:ClearBindings()
        end
        return
    end
    if event == "GLOBAL_MOUSE_DOWN" then ns.Fishing:HandleGlobalMouseDown(...) return end
    if event == "GLOBAL_MOUSE_UP" then ns.Fishing:HandleGlobalMouseUp(...) return end
    if event == "UNIT_AURA" then
        local unit = ...
        if unit == "player" then
            if ns.Alerts and ns.Alerts.CheckPatientChest then
                ns.Alerts:CheckPatientChest()
            end
            -- Lure depletion → auto-attach if configured
            if ns.DB and ns.DB.profile.alerts.autoAttachLure and ns.Fishing:HasLureTarget() then
                local lureNow = ns.Fishing:GetLureState()
                if ns.state.lastKnownLureActive and not lureNow.active then
                    ns:ScheduleTimer(function() ns.Fishing:TryAutoAttachLure("depletion") end, 0.3)
                end
                ns.state.lastKnownLureActive = lureNow.active
            end
        end
        return
    end
end

eventFrame:SetScript("OnEvent", function(_, event, ...)
    local args = { ... }
    local ok, err = xpcall(function()
        handleEvent(event, unpack(args))
    end, function(e)
        return tostring(e or "Unknown error") .. "\n" .. (debugstack and debugstack(2, 7, 7) or "")
    end)
    if not ok then
        if ns.Debug and ns.Debug.Capture and ns.DB then
            ns.Debug:Capture("Event:" .. tostring(event), err)
        else
            -- DB not yet initialised: surface the error so it appears in FrameXML.log
            geterrorhandler()(tostring(err))
        end
    end
end)

eventFrame:SetScript("OnUpdate", function(_, elapsed)
    local ok, err = xpcall(function()
        if ns.Core and ns.Core.OnUpdate then
            ns.Core:OnUpdate(elapsed)
        end
    end, function(e)
        return tostring(e or "Unknown error") .. "\n" .. (debugstack and debugstack(2, 7, 7) or "")
    end)
    if not ok and ns.Debug and ns.Debug.Capture then
        ns.Debug:Capture("OnUpdate", err)
    end
end)
