local function get_neighbours(pos)
  return {
    vector.new(pos.x + 1, pos.y, pos.z),
    vector.new(pos.x - 1, pos.y, pos.z),
    vector.new(pos.x + 1, pos.y + 1, pos.z),
    vector.new(pos.x + 1, pos.y - 1, pos.z),
    vector.new(pos.x - 1, pos.y - 1, pos.z),
    vector.new(pos.x - 1, pos.y + 1, pos.z),

    vector.new(pos.x, pos.y, pos.z + 1),
    vector.new(pos.x, pos.y, pos.z - 1),
    vector.new(pos.x, pos.y + 1, pos.z + 1),
    vector.new(pos.x, pos.y - 1, pos.z + 1),
    vector.new(pos.x, pos.y + 1, pos.z - 1),
    vector.new(pos.x, pos.y - 1, pos.z - 1),

    vector.new(pos.x, pos.y + 1, pos.z),
    vector.new(pos.x, pos.y - 1, pos.z),
  }
end

PyuTestCore.make_button = function (id, desc, groups, tiles)
  PyuTestCore.make_node(id, desc, PyuTestCore.util.tableconcat(groups, {
    electricity = 1
  }), tiles, {
    is_ground_content = false,
    on_rightclick = function (pos, node, clicker)
      for _, v in pairs(get_neighbours(pos)) do
        local n = minetest.get_node(v)
        local def = minetest.registered_nodes[n.name]

        if def.__on_electricity_activated then
          def.__on_electricity_activated(v, n, clicker, pos)
        end
      end

      minetest.sound_play("button", {
        pos = pos,
        gain = 1
      })
    end
  })
end

PyuTestCore.make_wire = function (id, desc, groups, color, efn)
  local fn = efn or function (def, pos, node, clicker, sender_pos)
    def.__on_electricity_activated(pos, node, clicker, sender_pos)
  end

  PyuTestCore.make_node(id, desc, PyuTestCore.util.tableconcat(groups, {
    electricity = 1
  }), {"pyutest-wire.png"}, {
    drawtype = "signlike",
    color = color,
    paramtype = "light",
    sunlight_propagates = true,
    selection_box = {
      type = "wallmounted"
    },
    walkable = false,
    inventory_image = "pyutest-wire.png",

    __on_electricity_activated = function (pos, node, clicker, sender_pos)
      for _, v in pairs(get_neighbours(pos)) do
        local n = minetest.get_node(v)
        local def = minetest.registered_nodes[n.name]

        -- To prevent infinite loops
        if v == sender_pos then
          goto continue
        end

        if def.__on_electricity_activated then
          fn(def, v, n, clicker, pos)
        end

        ::continue::
      end
    end
  })
end

PyuTestCore.make_button("pyutest_core:button", "Button", {
  cracky = PyuTestCore.BLOCK_NORMAL,
}, {"pyutest-button.png"})

PyuTestCore.make_wire("pyutest_core:copper_wire", "Copper Wire", {
  snappy = PyuTestCore.BLOCK_NORMAL
}, "darkgoldenrod")

PyuTestCore.make_wire("pyutest_core:delayer_wire", "Delayer Wire", {
  snappy = PyuTestCore.BLOCK_NORMAL
}, PyuTestCore.COLORS["blue"][2], function (def, pos, node, clicker, sender_pos)
  minetest.after(0.2, function ()
    def.__on_electricity_activated(pos, node, clicker, sender_pos)
  end)
end)

PyuTestCore.make_node("pyutest_core:test_device", "Test Device", {
  choppy = PyuTestCore.BLOCK_FAST,
  electricity = 1
}, {"pyutest-wood.png"}, {
  __on_electricity_activated = function(pos, node, clicker)
    minetest.add_item(pos + vector.new(0, 1, 0), ItemStack("pyutest_core:apple 1"))
  end
})

PyuTestCore.make_node("pyutest_core:freezer_device", "Freezer Device", {
  cracky = PyuTestCore.BLOCK_FAST,
  electricity = 1
}, {"pyutest-freezer.png"}, {
  __on_electricity_activated = function(pos, node, clicker)
    PyuTestCore.dorange(pos, 2, function (p)
      local n = minetest.get_node(p)

      if minetest.get_item_group(n.name, "freezable") ~= 0 then
        minetest.set_node(p, {name = "pyutest_core:ice_block"})
      end
    end)
  end
})

PyuTestCore.make_node("pyutest_core:heater_device", "Heater Device", {
  cracky = PyuTestCore.BLOCK_FAST,
  electricity = 1
}, {"pyutest-heater.png"}, {
  __on_electricity_activated = function(pos, node, clicker)
    PyuTestCore.dorange(pos, 2, function (p)
      local n = minetest.get_node(p)

      if minetest.get_item_group(n.name, "thawable") ~= 0 then
        local def = minetest.registered_nodes[n.name]
        local thaw_into = def.__thaw_into or "pyutest_core:water_source"
        minetest.set_node(p, {name = thaw_into})
      end
    end)
  end
})

minetest.register_craft({
  output = "pyutest_core:copper_wire 4",
  recipe = {
    "pyutest_core:copper_ingot"
  },
  type = "shapeless"
})

minetest.register_craft({
  output = "pyutest_core:delayer_wire",
  recipe = {
    "pyutest_core:copper_wire", "pyutest_core:blue_dye"
  },
  type = "shapeless"
})

minetest.register_craft({
  output = "pyutest_core:button",
  recipe = {
    {"pyutest_core:stone_block", "pyutest_core:stone_block", "pyutest_core:stone_block"},
    {"pyutest_core:stone_block", "pyutest_core:copper_ingot", "pyutest_core:stone_block"},
    {"pyutest_core:stone_block", "pyutest_core:stone_block", "pyutest_core:stone_block"}
  },
})

minetest.register_craft({
  output = "pyutest_core:freezer_device",
  recipe = {
    {"pyutest_core:stone_block", "pyutest_core:stone_block", "pyutest_core:stone_block"},
    {"pyutest_core:stone_block", "pyutest_core:ice_block", "pyutest_core:stone_block"},
    {"pyutest_core:stone_block", "pyutest_core:stone_block", "pyutest_core:stone_block"}
  },
})
