// Infinity’s stock datapack polled every player inventory with NBT selectors
// every tick. InventoryChanged is already emitted when a map or stone enters
// a slot, so handle those rare operations at the event boundary instead.

const infinityMaps = {
  sanctummap: { dimension: 'minecraft:overworld', modifier: 'sanctum_map', rename: 'rename_map_sanctum' },
  norsemap: { dimension: 'minecraft:overworld', modifier: 'norse_map', rename: 'rename_map_norse' },
  moragmap: { dimension: 'infinity:morag', modifier: 'morag_map', rename: 'rename_map_morag' },
  aethermap: { dimension: 'infinity:svartelheim', modifier: 'aether_map', rename: 'rename_map_aether' },
  sanctuarymap: { dimension: 'minecraft:the_end', modifier: 'sanctuary_map', rename: 'rename_map_sanctuary' }
}

const infinityStones = {
  'infinity:power_stone': 'power_stone',
  'infinity:space_stone': 'space_stone',
  'infinity:reality_stone': 'reality_stone',
  'infinity:time_stone': 'time_stone',
  'infinity:soul_stone': 'soul_stone',
  'infinity:mind_stone': 'mind_stone'
}

const mapProcessing = new Set()

function getMapMarker(item) {
  if (!item || item.id !== 'minecraft:map' || !item.nbt) return null

  for (const key in infinityMaps) {
    const value = item.nbt[key]
    if (value == 1 || value === true) return key
  }

  return null
}

function processInfinityMap(event, item) {
  const marker = getMapMarker(item)
  if (!marker) return

  const map = infinityMaps[marker]
  const player = event.getPlayer()
  const slot = event.getSlot()
  if (!player || slot < 0 || slot > 35) return

  let dimension
  try {
    dimension = String(player.level.dimension().location())
  } catch (error) {
    return
  }

  // Match the stock functions: a marker is converted only in the dimension
  // whose structure it points toward.
  if (dimension !== map.dimension) return

  const guard = String(player.getUUID()) + ':' + slot + ':' + marker
  if (mapProcessing.has(guard)) return
  mapProcessing.add(guard)

  try {
    // Remove the one-shot marker before modifying the slot so the inventory
    // event cannot recursively schedule the same conversion.
    try {
      item.nbt.remove(marker)
    } catch (error) {
      // The item modifier still produces the correct map if this is a copied
      // event stack rather than the live inventory stack.
    }

    const targetSlot = slot < 9 ? 'hotbar.' + slot : 'inventory.' + (slot - 9)
    player.runCommandSilent('item modify entity @s ' + targetSlot + ' infinity:' + map.modifier)
    player.runCommandSilent('item modify entity @s ' + targetSlot + ' infinity:' + map.rename)
  } finally {
    mapProcessing.delete(guard)
  }
}

PlayerEvents.inventoryChanged(event => {
  const item = event.getItem()
  if (!item) return

  processInfinityMap(event, item)

  const stone = infinityStones[item.id]
  if (!stone) return

  const player = event.getPlayer()
  if (item.count > 1) {
    // Keep the original duplicate-stone safeguard without an entity-NBT
    // selector. This command removes one extra copy from the changed stack.
    player.runCommandSilent('clear @s ' + item.id + ' 1')
  }

  // Remove display entities as soon as their corresponding stone is picked up.
  player.runCommandSilent('kill @e[type=armor_stand,tag=' + stone + '_ground,distance=..96]')
  player.runCommandSilent('kill @e[type=minecraft:interaction,tag=' + stone + '_ground_interaction,distance=..96]')
})
