if Bridge.Inventory.Name ~= "jpr" then
    return
end

if Bridge.Framework.GetName() ~= "qb" then
    error("[sky_phone] jpr-inventory is only supported with QBCore.")
end

local inventory = exports["jpr-inventory"]
local QBCore = exports["qb-core"]:GetCoreObject()

local function normalize(item, fallback_slot)
    local normalized = Bridge.Inventory.NormalizeItem(item, "info", fallback_slot)
    if not normalized or not normalized.name or normalized.amount < 1 then
        return nil
    end
    return normalized
end

local function get_inventory(source)
    local player = QBCore.Functions.GetPlayer(tonumber(source))
    return player and player.PlayerData.items or {}
end

local function restore_slot(source, slot, metadata)
    local restored = inventory:AddItem(source, slot.name, slot.amount, slot.slot, metadata, "sky_phone:metadata-rollback")
    if not restored then
        Bridge.Debug(
            "error",
            "[sky_phone] jpr-inventory could not restore item '%s' in slot %s after a metadata update failed.",
            tostring(slot.name),
            tostring(slot.slot)
        )
    end
    return restored == true
end

function Bridge.Inventory.GetResourceName()
    return "jpr-inventory"
end

function Bridge.Inventory.GetSlot(source, slot_id)
    local numeric_slot = tonumber(slot_id)
    return numeric_slot and normalize(inventory:GetItemBySlot(source, numeric_slot), numeric_slot) or nil
end

function Bridge.Inventory.GetSlotsWithItem(source, item_name, metadata)
    local matches = {}
    for index, item in pairs(get_inventory(source)) do
        local normalized = normalize(item, tonumber(index) or index)
        if normalized and normalized.name == item_name
            and Bridge.Inventory.MetadataMatches(normalized.metadata, metadata) then
            normalized.slot = normalized.slot or tonumber(index) or index
            matches[#matches + 1] = normalized
        end
    end
    return matches
end

function Bridge.Inventory.SetSlotMetadata(source, slot_id, metadata)
    local slot = Bridge.Inventory.GetSlot(source, slot_id)
    if not slot or slot.amount < 1 then
        return false
    end

    local previous_metadata = slot.metadata
    local requested_metadata = type(metadata) == "table" and metadata or {}
    if inventory:RemoveItem(source, slot.name, slot.amount, slot.slot, "sky_phone:metadata-update") ~= true then
        return false
    end
    if inventory:AddItem(source, slot.name, slot.amount, slot.slot, requested_metadata, "sky_phone:metadata-update") ~= true then
        restore_slot(source, slot, previous_metadata)
        return false
    end

    local updated = Bridge.Inventory.GetSlot(source, slot.slot)
    if updated and Bridge.Inventory.MetadataMatches(updated.metadata, requested_metadata) then
        return true
    end

    inventory:RemoveItem(source, slot.name, slot.amount, slot.slot, "sky_phone:metadata-rollback")
    restore_slot(source, slot, previous_metadata)
    return false
end

function Bridge.Inventory.CanCarryItem()
    return true
end

function Bridge.Inventory.AddItem(source, item_name, count, slot, metadata)
    return inventory:AddItem(source, item_name, count, slot, metadata or {}, "sky_phone") == true
end

function Bridge.Inventory.RemoveItem(source, item_name, count, slot, metadata)
    if metadata and not slot then
        local slots = Bridge.Inventory.GetSlotsWithItem(source, item_name, metadata)
        slot = slots[1] and slots[1].slot or nil
        if not slot then
            return 0
        end
    end
    return inventory:RemoveItem(source, item_name, count, slot, "sky_phone") == true and count or 0
end

function Bridge.Inventory.RegisterUsableItem(item_name, callback)
    return Bridge.Framework.RegisterUsableItem(item_name, function(source, ...)
        callback(source, normalize(Bridge.Inventory.ResolveUsableItem(...)))
    end)
end
