local event_handlers = {}

AddEventHandler = function(event_name, callback)
    event_handlers[event_name] = callback
end

local function reset_bridge(inventory_name, unique_phones, sim_cards_enabled)
    Config = {
        Bridge = {
            Inventory = inventory_name,
        },
        Phone = {
            Unique = unique_phones,
        },
        Sim = {
            Enabled = sim_cards_enabled,
        },
    }
    Bridge = {
        Debug = function()
        end,
        Framework = {
            GetName = function()
                return inventory_name == "esx" and "esx" or "qb"
            end,
        },
        Inventory = {},
    }
end

local function load_inventory_contract(adapter_path)
    dofile("sky_phone/source/bridge/server/inventory.lua")
    dofile(adapter_path)
    dofile("sky_phone/source/bridge/server/inventory_contract.lua")
end

local core_items = {
    {
        name = "phone",
        slot = 15,
        count = 1,
        metadata = {},
    },
}
local metadata_write
local core_inventory = {}

function core_inventory:getInventory(source)
    assert(source == 7)
    return core_items
end

function core_inventory:setMetadata(source, slot, metadata)
    metadata_write = { source = source, slot = slot, metadata = metadata }
    core_items[1].metadata = metadata
end

function core_inventory:updateMetadata()
    error("core bridge must use the stable setMetadata contract")
end

reset_bridge("core", true, true)
exports = {
    core_inventory = core_inventory,
}
GetResourceState = function(resource_name)
    return resource_name == "core_inventory" and "started" or "missing"
end
load_inventory_contract("sky_phone/source/bridge/server/inventory/core.lua")

assert(Bridge.Inventory.SetSlotMetadata(7, "15", { imei = "123456789012345" }))
assert(metadata_write.source == 7)
assert(metadata_write.slot == 15, "core metadata slot must be numeric")
assert(metadata_write.metadata.imei == "123456789012345")
assert(Bridge.Inventory.GetSlot(7, 15).metadata.imei == "123456789012345")

local qb_item = {
    name = "phone",
    slot = 2,
    amount = 1,
    info = { owner = "kept" },
}
local qb_write_mode = "persist"
local qb_inventory = {}

function qb_inventory:GetItemBySlot(source, slot)
    assert(source == 9 and slot == 2)
    return qb_item
end

function qb_inventory:GetItemsByName(source, item_name)
    assert(source == 9 and item_name == "phone")
    return qb_item and { qb_item } or {}
end

function qb_inventory:SetItemData()
    error("qb bridge must not rely on an unverified direct metadata setter")
end

function qb_inventory:RemoveItem(source, item_name, amount, slot, reason)
    assert(source == 9 and item_name == "phone" and amount == 1 and slot == 2)
    assert(reason == "sky_phone:metadata-update")
    if not qb_item then
        return false
    end
    qb_item = nil
    return true
end

function qb_inventory:AddItem(source, item_name, amount, slot, info, reason)
    assert(source == 9 and item_name == "phone" and amount == 1 and slot == 2)
    assert(reason == "sky_phone:metadata-update")
    qb_item = {
        name = item_name,
        slot = slot,
        amount = amount,
        info = qb_write_mode == "drop_metadata" and {} or info,
    }
    return true
end

function qb_inventory:CanAddItem()
    return true
end

reset_bridge("qb", true, true)
exports = {
    ["qb-inventory"] = qb_inventory,
}
GetResourceState = function(resource_name)
    return resource_name == "qb-inventory" and "started" or "missing"
end
load_inventory_contract("sky_phone/source/bridge/server/inventory/qb.lua")

assert(Bridge.Inventory.SetSlotMetadata(9, 2, { owner = "kept", imei = "123456789012345" }))
assert(qb_item.info.owner == "kept" and qb_item.info.imei == "123456789012345")

qb_write_mode = "drop_metadata"
assert(not Bridge.Inventory.SetSlotMetadata(9, 2, { owner = "kept", imei = "999999999999999" }))
assert(qb_item and qb_item.slot == 2, "QB metadata verification must leave the item in its exact slot")

local function create_esx()
    local usable_items = {}
    local player = {}

    function player.getInventoryItem(item_name)
        return {
            name = item_name,
            count = 1,
        }
    end

    local esx = {}

    function esx.GetPlayerFromId(source)
        assert(source == 11)
        return player
    end

    function esx.RegisterUsableItem(item_name, callback)
        usable_items[item_name] = callback
    end

    return esx, usable_items
end

local esx, usable_items = create_esx()
reset_bridge("esx", false, false)
exports = {
    es_extended = {
        getSharedObject = function()
            return esx
        end,
    },
}
GetResourceState = function(resource_name)
    return resource_name == "es_extended" and "started" or "missing"
end
load_inventory_contract("sky_phone/source/bridge/server/inventory/esx.lua")

local used_item
assert(Bridge.Inventory.RegisterUsableItem("phone", function(source, item)
    assert(source == 11)
    used_item = item
end))
usable_items.phone(11)
assert(used_item.name == "phone")
assert(used_item.slot == "phone")
assert(used_item.count == 1)

esx = create_esx()
reset_bridge("esx", true, true)
exports = {
    es_extended = {
        getSharedObject = function()
            return esx
        end,
    },
}
load_inventory_contract("sky_phone/source/bridge/server/inventory/esx.lua")

assert(Config.Phone.Unique == false)
assert(Config.Sim.Enabled == false)
assert(Bridge.Inventory.ConfigurationError == nil)

Config.Phone.Unique = true
Config.Sim.Enabled = true
event_handlers["sky_phone:configurator:serverUpdated"]()
assert(Config.Phone.Unique == false)
assert(Config.Sim.Enabled == false)

assert(Bridge.Inventory.RegisterUsableItem("phone", function()
end))

local manifest_file = assert(io.open("sky_phone/fxmanifest.lua", "rb"))
local manifest = manifest_file:read("*a")
manifest_file:close()
local adapters = assert(manifest:find("source/bridge/server/inventory/*.lua", 1, true))
local contract = assert(manifest:find("source/bridge/server/inventory_contract.lua", 1, true))
assert(adapters < contract, "inventory contract must load after provider adapters")

print("inventory bridge regression checks passed")
