```python
import bpy
import math
import bmesh

# -----------------------------------------------------------------------------
# Scene Setup
# -----------------------------------------------------------------------------
def clean_scene():
    """Remove all objects from the current scene."""
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)

def setup_render():
    """Set render engine and general settings."""
    scene = bpy.context.scene
    scene.render.engine = 'CYCLES'
    scene.render.resolution_x = 1920
    scene.render.resolution_y = 1080
    scene.render.fps = 24
    scene.view_settings.view_transform = 'Filmic'
    scene.view_settings.look = 'None'
    scene.cycles.samples = 128
    scene.cycles.use_denoising = True
    scene.render.film_transparent = False

def setup_world():
    """Dark, calm background."""
    world = bpy.context.scene.world
    world.use_nodes = True
    bg = world.node_tree.nodes['Background']
    bg.inputs[0].default_value = (0.005, 0.005, 0.01, 1.0)
    bg.inputs[1].default_value = 1.0

# -----------------------------------------------------------------------------
# Material helpers
# -----------------------------------------------------------------------------
def make_material(name, color=(0.8, 0.8, 0.8, 1.0), metallic=0.0, roughness=0.5,
                  emission_color=None, emission_strength=0.0,
                  transmission=0.0, ior=1.45):
    mat = bpy.data.materials.new(name)
    mat.use_nodes = True
    bsdf = mat.node_tree.nodes['Principled BSDF']
    bsdf.inputs['Base Color'].default_value = color
    bsdf.inputs['Metallic'].default_value = metallic
    bsdf.inputs['Roughness'].default_value = roughness
    bsdf.inputs['Transmission Weight'].default_value = transmission
    bsdf.inputs['IOR'].default_value = ior
    if emission_color is not None:
        bsdf.inputs['Emission Color'].default_value = emission_color
        bsdf.inputs['Emission Strength'].default_value = emission_strength
    return mat

def apply_materials(obj, mat):
    obj.data.materials.clear()
    obj.data.materials.append(mat)

# -----------------------------------------------------------------------------
# Geometry helpers
# -----------------------------------------------------------------------------
def add_cylinder(name, location, radius, depth, rotation=(0,0,0),
                 vertices=32, end_fill_type='NGON'):
    bpy.ops.mesh.primitive_cylinder_add(
        vertices=vertices,
        radius=radius,
        depth=depth,
        end_fill_type=end_fill_type,
        location=location,
        rotation=rotation
    )
    obj = bpy.context.active_object
    obj.name = name
    return obj

def add_sphere(name, location, radius):
    bpy.ops.mesh.primitive_uv_sphere_add(radius=radius, location=location)
    obj = bpy.context.active_object
    obj.name = name
    return obj

def add_torus(name, location, major_radius, minor_radius):
    bpy.ops.mesh.primitive_torus_add(
        location=location,
        major_radius=major_radius,
        minor_radius=minor_radius
    )
    obj = bpy.context.active_object
    obj.name = name
    return obj

# -----------------------------------------------------------------------------
# Build the scene
# -----------------------------------------------------------------------------
def build_scene():
    global ground, base, fount, burner, gen, core
    global glass, bar, empty, rim_bottom, rim_top
    global top_disk, top_cone, knob, handle, hinge_l, hinge_r, valve

    # --- Materials ---
    metal_base   = make_material("Metal Base",
                                 color=(0.20, 0.15, 0.10, 1.0),
                                 metallic=1.0, roughness=0.5)
    metal_frame  = make_material("Metal Frame",
                                 color=(0.40, 0.35, 0.30, 1.0),
                                 metallic=1.0, roughness=0.4)
    metal_handle = make_material("Metal Handle",
                                 color=(0.30, 0.25, 0.20, 1.0),
                                 metallic=1.0, roughness=0.6)
    glass_mat    = make_material("Glass",
                                 color=(0.95, 0.97, 1.00, 1.0),
                                 roughness=0.02, transmission=1.0, ior=1.45)
    core_mat     = make_material("Core",
                                 color=(0.0, 0.0, 0.0, 1.0),
                                 roughness=0.0,
                                 emission_color=(1.0, 0.5, 0.1, 1.0),
                                 emission_strength=80.0)
    ground_mat   = make_material("Ground",
                                 color=(0.015, 0.015, 0.015, 1.0),
                                 roughness=0.9)

    # --- Ground ---
    bpy.ops.mesh.primitive_plane_add(size=10, location=(0, 0, -0.3))
    ground = bpy.context.active_object
    ground.name = "Ground"
    apply_materials(ground, ground_mat)

    # --- Base ---
    base = add_cylinder("Base", location=(0, 0, -0.25),
                        radius=0.4, depth=0.1)
    apply_materials(base, metal_base)
    bpy.ops.object.shade_smooth()

    # --- Fuel Fount ---
    fount = add_cylinder("Fount", location=(0, 0, -0.05),
                         radius=0.25, depth=0.3)
    apply_materials(fount, metal_base)
    bpy.ops.object.shade_smooth()

    # --- Valve (detail) ---
    valve = add_cylinder("Valve", location=(0.20, 0, 0.00),
                         radius=0.04, depth=0.15,
                         rotation=(0, math.pi/2, 0))
    apply_materials(valve, metal_frame)

    # --- Burner ---
    burner = add_cylinder("Burner", location=(0, 0, 0.15),
                          radius=0.18, depth=0.15)
    apply_materials(burner, metal_frame)
    bpy.ops.object.shade_smooth()

    # --- Generator ---
    gen = add_cylinder("Generator", location=(0, 0, 0.25),
                       radius=0.06, depth=0.15)
    apply_materials(gen, metal_frame)

    # --- Mantle (core) ---
    core = add_sphere("Mantle", location=(0, 0, 0.5), radius=0.15)
    apply_materials(core, core_mat)
    bpy.ops.object.modifier_add(type='SUBSURF')
    core.modifiers[0].levels = 2
    bpy.ops.object.shade_smooth()

    # --- Glass enclosure ---
    glass = add_cylinder("Glass", location=(0, 0, 0.5),
                         radius=0.35, depth=0.6,
                         end_fill_type='NOTHING')
    apply_materials(glass, glass_mat)
    bpy.ops.object.modifier_add(type='SOLIDIFY')
    glass.modifiers[0].thickness = 0.02
    glass.modifiers[0].offset = -1

    # --- Glass rims ---
    rim_bottom = add_cylinder("Rim Bottom", location=(0, 0, 0.2),
                              radius=0.37, depth=0.02)
    apply_materials(rim_bottom, metal_frame)
    rim_top = add_cylinder("Rim Top", location=(0, 0, 0.8),
                           radius=0.37, depth=0.02)
    apply_materials(rim_top, metal_frame)

    # --- Cage bars (array of 4) ---
    bar = add_cylinder("Cage Bar", location=(0.4, 0, 0.5),
                       radius=0.015, depth=0.6, vertices=8)
    apply_materials(bar, metal_frame)
    bpy.ops.object.modifier_add(type='ARRAY')
    bar.modifiers[0].count = 4
    bar.modifiers[0].relative_offset_displace = (0,0,0)
    bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0,0,0))
    empty = bpy.context.active_object
    empty.name = "Array Empty"
    bar.modifiers[0].use_relative_offset = False
    bar.modifiers[0].use_object_offset = True
    bar.modifiers[0].offset_object = empty
    empty.rotation_euler[2] = math.pi / 2

    # --- Top cap ---
    top_disk = add_cylinder("Top Disk", location=(0, 0, 0.83),
                            radius=0.3, depth=0.03)
    apply_materials(top_disk, metal_frame)

    bpy.ops.mesh.primitive_cone_add(vertices=32, radius1=0.2, depth=0.15,
                                    location=(0, 0, 0.93))
    top_cone = bpy.context.active_object
    top_cone.name = "Top Cone"
    apply_materials(top_cone, metal_frame)

    knob = add_cylinder("Knob", location=(0, 0, 1.02),
                        radius=0.08, depth=0.05)
    apply_materials(knob, metal_frame)

    # --- Carry handle (arc) ---
    handle = add_torus("Handle", location=(0, 0, 1.1),
                       major_radius=0.3, minor_radius=0.025)
    apply_materials(handle, metal_handle)

    bpy.ops.object.mode_set(mode='EDIT')
    bm = bmesh.from_edit_mesh(handle.data)
    for v in bm.verts:
        if v.co.z < 0.0:   # local space – cut the lower half
            v.select = True
    bmesh.update_edit_mesh(handle.data)
    bpy.ops.mesh.delete(type='VERT')
    bpy.ops.object.mode_set(mode='OBJECT')

    # --- Hinges ---
    hinge_l = add_cylinder("Hinge L", location=(0.3, 0, 0.82),
                           radius=0.03, depth=0.08,
                           rotation=(0, math.pi/2, 0))
    apply_materials(hinge_l, metal_handle)

    hinge_r = add_cylinder("Hinge R", location=(-0.3, 0, 0.82),
                           radius=0.03, depth=0.08,
                           rotation=(0, math.pi/2, 0))
    apply_materials(hinge_r, metal_handle)

    bpy.ops.object.select_all(action='DESELECT')

# -----------------------------------------------------------------------------
# Lighting
# -----------------------------------------------------------------------------
def setup_lights():
    # Main source: point lamp inside the glowing core
    bpy.ops.object.light_add(type='POINT', location=(0, 0, 0.5))
    core_lamp = bpy.context.active_object
    core_lamp.name = "Core Light"
    core_lamp.data.energy = 150
    core_lamp.data.color = (1.0, 0.7, 0.3)

    # Soft cool fill to separate the metal from the dark background
    bpy.ops.object.light_add(type='AREA', location=(-2, 2, 1.5))
    fill_lamp = bpy.context.active_object
    fill_lamp.name = "Fill Light"
    fill_lamp.data.energy = 30
    fill_lamp.data.color = (0.8, 0.9, 1.0)
    fill_lamp.data.size = 2
    fill_lamp.rotation_euler = (0.5, -0.2, 1.2)

# -----------------------------------------------------------------------------
# Camera
# -----------------------------------------------------------------------------
def setup_camera():
    bpy.ops.object.camera_add(location=(1.8, -1.4, 0.7))
    cam = bpy.context.active_object
    cam.name = "Main Camera"
    cam.data.lens = 50
    bpy.context.scene.camera = cam

    # Track to centre of the lantern
    bpy.ops.object.constraint_add(type='TRACK_TO')
    cam.constraints["Track To"].target = top_disk
    cam.constraints["Track To"].track_axis = 'TRACK_NEGATIVE_Z'
    cam.constraints["Track To"].up_axis = 'UP_Y'

# -----------------------------------------------------------------------------
# Apply modifiers for clean GLB export
# -----------------------------------------------------------------------------
def apply_modifiers():
    bpy.ops.object.select_all(action='DESELECT')

    # Cage bar array
    bpy.context.view_layer.objects.active = bar
    bpy.ops.object.modifier_apply(modifier=bar.modifiers[0].name)

    # Glass solidify
    bpy.context.view_layer.objects.active = glass
    bpy.ops.object.modifier_apply(modifier=glass.modifiers[0].name)

    # Core subsurf
    bpy.context.view_layer.objects.active = core
    bpy.ops.object.modifier_apply(modifier=core.modifiers[0].name)

    # Clean up the empty used by the array
    if empty.name in bpy.data.objects:
        bpy.data.objects.remove(empty, do_unlink=True)

# -----------------------------------------------------------------------------
# Main execution
# -----------------------------------------------------------------------------
clean_scene()
setup_render()
setup_world()
build_scene()
setup_lights()
setup_camera()
apply_modifiers()

print("Lantern scene built successfully!")
```