```python
import bpy
import math
import mathutils

def setup_scene():
    # Clear existing objects and data
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(full=False)

    for block in [bpy.data.meshes, bpy.data.materials, bpy.data.textures,
                  bpy.data.images, bpy.data.lights, bpy.data.curves, bpy.data.cameras]:
        for item in block:
            block.remove(item)

    # Render settings
    scene = bpy.context.scene
    scene.render.engine = 'CYCLES'

    # Color management
    if hasattr(scene, 'display_settings'):
        scene.display_settings.display_device = 'sRGB'
    if hasattr(scene, 'view_settings'):
        try:
            scene.view_settings.view_transform = 'AgX'
        except Exception:
            scene.view_settings.view_transform = 'Filmic'
        scene.view_settings.look = 'Medium High Contrast'

    # World background
    world = bpy.data.worlds.new("DarkStudioWorld")
    world.use_nodes = True
    bg_node = world.node_tree.nodes.get("Background")
    if bg_node:
        bg_node.inputs['Color'].default_value = (0.008, 0.01, 0.015, 1.0)
        bg_node.inputs['Strength'].default_value = 0.5
    scene.world = world

# Helper to safely set Principled BSDF socket values
def set_socket_val(node, socket_names, value):
    for name in socket_names:
        if name in node.inputs:
            node.inputs[name].default_value = value
            return True
    return False

# Materials
def create_materials():
    mats = {}

    # 1. Vintage Green Enamel (Hood & Tank)
    mat_green = bpy.data.materials.new(name="Vintage_Green_Enamel")
    mat_green.use_nodes = True
    nodes = mat_green.node_tree.nodes
    links = mat_green.node_tree.links
    nodes.clear()

    out = nodes.new('ShaderNodeOutputMaterial')
    bsdf = nodes.new('ShaderNodeBsdfPrincipled')
    set_socket_val(bsdf, ['Base Color'], (0.012, 0.082, 0.035, 1.0)) # Iconic dark green
    set_socket_val(bsdf, ['Roughness'], 0.18)
    set_socket_val(bsdf, ['Metallic'], 0.0)
    set_socket_val(bsdf, ['Coat Weight', 'Clearcoat'], 0.5)

    noise = nodes.new('ShaderNodeTexNoise')
    noise.inputs['Scale'].default_value = 150.0
    bump = nodes.new('ShaderNodeBump')
    bump.inputs['Strength'].default_value = 0.012
    links.new(noise.outputs['Factor'], bump.inputs['Height'])
    links.new(bump.outputs['Normal'], bsdf.inputs['Normal'])
    links.new(bsdf.outputs['BSDF'], out.inputs['Surface'])
    mats['green'] = mat_green

    # 2. Chrome / Steel Metal (Cage Guard & Handle)
    mat_chrome = bpy.data.materials.new(name="Chrome_Steel")
    mat_chrome.use_nodes = True
    nodes = mat_chrome.node_tree.nodes
    links = mat_chrome.node_tree.links
    nodes.clear()

    out = nodes.new('ShaderNodeOutputMaterial')
    bsdf = nodes.new('ShaderNodeBsdfPrincipled')
    set_socket_val(bsdf, ['Base Color'], (0.85, 0.86, 0.88, 1.0))
    set_socket_val(bsdf, ['Metallic'], 0.98)
    set_socket_val(bsdf, ['Roughness'], 0.14)
    links.new(bsdf.outputs['BSDF'], out.inputs['Surface'])
    mats['chrome'] = mat_chrome

    # 3. Polished Brass (Valve, Nut & Accents)
    mat_brass = bpy.data.materials.new(name="Brass_Accent")
    mat_brass.use_nodes = True
    nodes = mat_brass.node_tree.nodes
    links = mat_brass.node_tree.links
    nodes.clear()

    out = nodes.new('ShaderNodeOutputMaterial')
    bsdf = nodes.new('ShaderNodeBsdfPrincipled')
    set_socket_val(bsdf, ['Base Color'], (0.92, 0.72, 0.32, 1.0))
    set_socket_val(bsdf, ['Metallic'], 0.95)
    set_socket_val(bsdf, ['Roughness'], 0.22)
    links.new(bsdf.outputs['BSDF'], out.inputs['Surface'])
    mats['brass'] = mat_brass

    # 4. Phenolic Red Valve Knob
    mat_red = bpy.data.materials.new(name="Red_Knob")
    mat_red.use_nodes = True
    nodes = mat_red.node_tree.nodes
    links = mat_red.node_tree.links
    nodes.clear()

    out = nodes.new('ShaderNodeOutputMaterial')
    bsdf = nodes.new('ShaderNodeBsdfPrincipled')
    set_socket_val(bsdf, ['Base Color'], (0.22, 0.02, 0.02, 1.0))
    set_socket_val(bsdf, ['Roughness'], 0.32)
    links.new(bsdf.outputs['BSDF'], out.inputs['Surface'])
    mats['red'] = mat_red

    # 5. Lantern Glass Globe (Physical refraction + shadow pass)
    mat_glass = bpy.data.materials.new(name="Lantern_Glass")
    mat_glass.use_nodes = True
    nodes = mat_glass.node_tree.nodes
    links = mat_glass.node_tree.links
    nodes.clear()

    out = nodes.new('ShaderNodeOutputMaterial')
    mix = nodes.new('ShaderNodeMixShader')

    bsdf = nodes.new('ShaderNodeBsdfPrincipled')
    set_socket_val(bsdf, ['Base Color'], (0.96, 0.98, 1.0, 1.0))
    set_socket_val(bsdf, ['Roughness'], 0.03)
    set_socket_val(bsdf, ['Transmission Weight', 'Transmission'], 1.0)
    set_socket_val(bsdf, ['IOR'], 1.48)

    transp = nodes.new('ShaderNodeBsdfTransparent')
    transp.inputs['Color'].default_value = (0.98, 0.96, 0.92, 1.0)

    lp = nodes.new('ShaderNodeLightPath')

    links.new(lp.outputs['Is Shadow Ray'], mix.inputs['Factor'])
    links.new(bsdf.outputs['BSDF'], mix.inputs[1])
    links.new(transp.outputs['BSDF'], mix.inputs[2])
    links.new(mix.outputs['Shader'], out.inputs['Surface'])
    mats['glass'] = mat_glass

    # 6. Glowing Mantle Core
    mat_mantle = bpy.data.materials.new(name="Mantle_Glow")
    mat_mantle.use_nodes = True
    nodes = mat_mantle.node_tree.nodes
    links = mat_mantle.node_tree.links
    nodes.clear()

    out = nodes.new('ShaderNodeOutputMaterial')
    bsdf = nodes.new('ShaderNodeBsdfPrincipled')
    set_socket_val(bsdf, ['Base Color'], (1.0, 0.65, 0.25, 1.0))
    set_socket_val(bsdf, ['Emission Color', 'Emission'], (1.0, 0.48, 0.10, 1.0))
    set_socket_val(bsdf, ['Emission Strength'], 35.0)
    links.new(bsdf.outputs['BSDF'], out.inputs['Surface'])
    mats['mantle'] = mat_mantle

    # 7. Ground Material (Dark slate / wooden deck surface)
    mat_ground = bpy.data.materials.new(name="Ground_Surface")
    mat_ground.use_nodes = True
    nodes = mat_ground.node_tree.nodes
    links = mat_ground.node_tree.links
    nodes.clear()

    out = nodes.new('ShaderNodeOutputMaterial')
    bsdf = nodes.new('ShaderNodeBsdfPrincipled')
    set_socket_val(bsdf, ['Base Color'], (0.045, 0.038, 0.032, 1.0))
    set_socket_val(bsdf, ['Roughness'], 0.52)

    mapping = nodes.new('ShaderNodeMapping')
    mapping.inputs['Scale'].default_value = (10.0, 10.0, 10.0)
    tex_coord = nodes.new('ShaderNodeTexCoord')

    noise = nodes.new('ShaderNodeTexNoise')
    noise.inputs['Scale'].default_value = 28.0
    noise.inputs['Detail'].default_value = 4.0

    bump = nodes.new('ShaderNodeBump')
    bump.inputs['Strength'].default_value = 0.035

    links.new(tex_coord.outputs['Object'], mapping.inputs['Vector'])
    links.new(mapping.outputs['Vector'], noise.inputs['Vector'])
    links.new(noise.outputs['Factor'], bump.inputs['Height'])
    links.new(bump.outputs['Normal'], bsdf.inputs['Normal'])
    links.new(bsdf.outputs['BSDF'], out.inputs['Surface'])
    mats['ground'] = mat_ground

    return mats

# Lathe Mesh Generation Helper
def create_lathe_mesh(name, profile_points, segments=32, close_top=False, close_bottom=False, mat=None):
    verts = []
    faces = []
    num_p = len(profile_points)

    for s in range(segments):
        angle = (2.0 * math.pi * s) / segments
        cos_a = math.cos(angle)
        sin_a = math.sin(angle)
        for r, z in profile_points:
            verts.append((r * cos_a, r * sin_a, z))

    for s in range(segments):
        next_s = (s + 1) % segments
        for p in range(num_p - 1):
            i1 = s * num_p + p
            i2 = s * num_p + (p + 1)
            i3 = next_s * num_p + (p + 1)
            i4 = next_s * num_p + p
            faces.append((i1, i4, i3, i2))

    if close_bottom:
        c_idx = len(verts)
        r_bot, z_bot = profile_points[0]
        verts.append((0, 0, z_bot))
        for s in range(segments):
            next_s = (s + 1) % segments
            faces.append((c_idx, next_s * num_p, s * num_p))

    if close_top:
        c_idx = len(verts)
        r_top, z_top = profile_points[-1]
        verts.append((0, 0, z_top))
        for s in range(segments):
            next_s = (s + 1) % segments
            faces.append((c_idx, s * num_p + (num_p - 1), next_s * num_p + (num_p - 1)))

    mesh = bpy.data.meshes.new(name)
    mesh.from_pydata(verts, [], faces)
    mesh.update()
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)

    for poly in mesh.polygons:
        poly.use_smooth = True

    if mat:
        obj.data.materials.append(mat)
    return obj

# Pipe/Ring Helper
def create_pipe_ring(name, radius, z, wire_radius=0.002, segments=32, ring_segments=12, mat=None):
    verts = []
    faces = []
    for s in range(segments):
        a = (2.0 * math.pi * s) / segments
        for rs in range(ring_segments):
            ra = (2.0 * math.pi * rs) / ring_segments
            r_off = wire_radius * math.cos(ra)
            rz = wire_radius * math.sin(ra)
            x = (radius + r_off) * math.cos(a)
            y = (radius + r_off) * math.sin(a)
            verts.append((x, y, z + rz))

    num_r = ring_segments
    for s in range(segments):
        next_s = (s + 1) % segments
        for rs in range(ring_segments):
            next_rs = (rs + 1) % ring_segments
            i1 = s * num_r + rs
            i2 = s * num_r + next_rs
            i3 = next_s * num_r + next_rs
            i4 = next_s * num_r + rs
            faces.append((i1, i4, i3, i2))

    mesh = bpy.data.meshes.new(name)
    mesh.from_pydata(verts, [], faces)
    mesh.update()
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)
    for p in mesh.polygons:
        p.use_smooth = True
    if mat:
        obj.data.materials.append(mat)
    return obj

# Curved Wire Tube Helper
def create_curved_wire(name, path_points, wire_radius=0.002, circle_segments=10, mat=None):
    verts = []
    faces = []
    num_pts = len(path_points)

    for i in range(num_pts):
        pt = mathutils.Vector(path_points[i])
        if i == 0:
            tangent = (mathutils.Vector(path_points[1]) - pt).normalized()
        elif i == num_pts - 1:
            tangent = (pt - mathutils.Vector(path_points[i-1])).normalized()
        else:
            tangent = (mathutils.Vector(path_points[i+1]) - mathutils.Vector(path_points[i-1])).normalized()

        up = mathutils.Vector((0, 0, 1))
        if abs(tangent.z) > 0.9:
            up = mathutils.Vector((1, 0, 0))
        normal = tangent.cross(up).normalized()
        binormal = tangent.cross(normal).normalized()

        for cs in range(circle_segments):
            angle = (2.0 * math.pi * cs) / circle_segments
            offset = (normal * math.cos(angle) + binormal * math.sin(angle)) * wire_radius
            v = pt + offset
            verts.append((v.x, v.y, v.z))

    for i in range(num_pts - 1):
        for cs in range(circle_segments):
            next_cs = (cs + 1) % circle_segments
            i1 = i * circle_segments + cs
            i2 = i * circle_segments + next_cs
            i3 = (i + 1) * circle_segments + next_cs
            i4 = (i + 1) * circle_segments + cs
            faces.append((i1, i4, i3, i2))

    mesh = bpy.data.meshes.new(name)
    mesh.from_pydata(verts, [], faces)
    mesh.update()
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)
    for p in mesh.polygons:
        p.use_smooth = True
    if mat:
        obj.data.materials.append(mat)
    return obj

# Build Complete Lantern Geometry
def build_lantern(mats):
    # 1. Fuel Tank Base
    tank_profile = [
        (0.090, 0.000),
        (0.090, 0.008),
        (0.086, 0.012),
        (0.086, 0.060),
        (0.082, 0.070),
        (0.058, 0.082),
        (0.058, 0.086)
    ]
    create_lathe_mesh("Fuel_Tank", tank_profile, segments=36, close_bottom=True, mat=mats['green'])

    # Fuel Cap on Tank
    bpy.ops.mesh.primitive_cylinder_add(radius=0.012, depth=0.014, location=(0.045, 0.045, 0.076))
    fuel_cap = bpy.context.active_object
    fuel_cap.name = "Fuel_Cap"
    fuel_cap.rotation_euler = (math.radians(22), math.radians(-22), 0)
    fuel_cap.data.materials.append(mats['brass'])

    # 2. Collar / Burner Base
    collar_profile = [
        (0.058, 0.086),
        (0.054, 0.090),
        (0.054, 0.124),
        (0.058, 0.128)
    ]
    create_lathe_mesh("Collar", collar_profile, segments=32, mat=mats['chrome'])

    # 3. Control Valve Stem & Red Knob
    bpy.ops.mesh.primitive_cylinder_add(radius=0.004, depth=0.032, location=(0.0, -0.062, 0.098))
    valve_stem = bpy.context.active_object
    valve_stem.name = "Valve_Stem"
    valve_stem.rotation_euler = (math.radians(90), 0, 0)
    valve_stem.data.materials.append(mats['brass'])

    bpy.ops.mesh.primitive_cylinder_add(radius=0.016, depth=0.006, location=(0.0, -0.084, 0.098))
    valve_knob = bpy.context.active_object
    valve_knob.name = "Valve_Knob"
    valve_knob.rotation_euler = (math.radians(90), 0, 0)
    valve_knob.data.materials.append(mats['red'])

    bpy.ops.mesh.primitive_cylinder_add(radius=0.004, depth=0.003, location=(0.0, -0.088, 0.098))
    knob_nut = bpy.context.active_object
    knob_nut.name = "Valve_Nut"
    knob_nut.rotation_euler = (math.radians(90), 0, 0)
    knob_nut.data.materials.append(mats['brass'])

    # 4. Glass Globe (Physical thickness)
    glass_profile = [
        (0.050, 0.128),
        (0.063, 0.155),
        (0.066, 0.183),
        (0.063, 0.211),
        (0.050, 0.238),
        (0.047, 0.238),
        (0.060, 0.211),
        (0.063, 0.183),
        (0.060, 0.155),
        (0.047, 0.128)
    ]
    create_lathe_mesh("Glass_Globe", glass_profile, segments=36, mat=mats['glass'])

    # 5. Glowing Mantle Core & Burner Head
    bpy.ops.mesh.primitive_cylinder_add(radius=0.006, depth=0.030, location=(0.0, 0.0, 0.223))
    burner_tube = bpy.context.active_object
    burner_tube.name = "Burner_Tube"
    burner_tube.data.materials.append(mats['brass'])

    bpy.ops.mesh.primitive_cylinder_add(radius=0.012, depth=0.010, location=(0.0, 0.0, 0.203))
    burner_head = bpy.context.active_object
    burner_head.name = "Burner_Head"
    burner_head.data.materials.append(mats['brass'])

    mantle_profile = [
        (0.002, 0.203),
        (0.012, 0.198),
        (0.016, 0.183),
        (0.014, 0.168),
        (0.002, 0.163)
    ]
    create_lathe_mesh("Mantle_Core", mantle_profile, segments=24, close_top=True, close_bottom=True, mat=mats['mantle'])

    # 6. Wire Protection Cage
    create_pipe_ring("Guard_Ring_Bottom", radius=0.052, z=0.133, wire_radius=0.0022, mat=mats['chrome'])
    create_pipe_ring("Guard_Ring_Top", radius=0.052, z=0.233, wire_radius=0.0022, mat=mats['chrome'])

    for ang in [45, 135, 225, 315]:
        rad = math.radians(ang)
        c, s = math.cos(rad), math.sin(rad)
        pts = [
            (0.052 * c, 0.052 * s, 0.133),
            (0.063 * c, 0.063 * s, 0.158),
            (0.067 * c, 0.067 * s, 0.183),
            (0.063 * c, 0.063 * s, 0.208),
            (0.052 * c, 0.052 * s, 0.233)
        ]
        create_curved_wire(f"Guard_Wire_{ang}", pts, wire_radius=0.0022, mat=mats['chrome'])

    # 7. Ventilator Top Hood
    hood_profile = [
        (0.050, 0.238),
        (0.054, 0.242),
        (0.092, 0.258),
        (0.092, 0.264),
        (0.060, 0.280),
        (0.058, 0.280),
        (0.058, 0.292),
        (0.068, 0.298),
        (0.068, 0.302),
        (0.035, 0.318),
        (0.012, 0.323)
    ]
    create_lathe_mesh("Ventilator_Hood", hood_profile, segments=36, close_top=True, mat=mats['green'])

    # Top Brass Finial Nut
    bpy.ops.mesh.primitive_cylinder_add(radius=0.010, depth=0.012, location=(0.0, 0.0, 0.327))
    finial = bpy.context.active_object
    finial.name = "Finial_Nut"
    finial.data.materials.append(mats['brass'])

    # Handle Attachments (Ears)
    for side in [-1, 1]:
        bpy.ops.mesh.primitive_cylinder_add(radius=0.004, depth=0.012, location=(side * 0.062, 0.0, 0.280))
        ear = bpy.context.active_object
        ear.name = f"Handle_Ear_{side}"
        ear.rotation_euler = (0, math.radians(90), 0)
        ear.data.materials.append(mats['brass'])

    # 8. Carry Handle (Bail Arc)
    bail_pts = []
    num_steps = 28
    for i in range(num_steps + 1):
        t = i / num_steps
        x = -0.064 * math.cos(t * math.pi)
        z = 0.280 + 0.098 * math.sin(t * math.pi)
        y = 0.0
        bail_pts.append((x, y, z))
    create_curved_wire("Carry_Handle", bail_pts, wire_radius=0.0025, mat=mats['chrome'])

# Build Ground & Environment
def build_environment(mats):
    # Floor Plane
    bpy.ops.mesh.primitive_plane_add(size=12.0, location=(0.0, 0.0, 0.0))
    floor = bpy.context.active_object
    floor.name = "Ground_Plane"
    floor.data.materials.append(mats['ground'])

    # Dark Curved Studio Backdrop
    backdrop_verts = [
        (-6.0, 1.5, 0.0), (6.0, 1.5, 0.0),
        (-6.0, 3.5, 1.2), (6.0, 3.5, 1.2),
        (-6.0, 4.5, 4.0), (6.0, 4.5, 4.0)
    ]
    backdrop_faces = [(0, 1, 3, 2), (2, 3, 5, 4)]
    mesh = bpy.data.meshes.new("Backdrop")
    mesh.from_pydata(backdrop_verts, [], backdrop_faces)
    mesh.update()
    obj = bpy.data.objects.new("Backdrop", mesh)
    bpy.context.collection.objects.link(obj)
    for p in mesh.polygons:
        p.use_smooth = True

    # Dark Slate Backdrop Material
    mat_bg = bpy.data.materials.new(name="Backdrop_Mat")
    mat_bg.use_nodes = True
    nodes = mat_bg.node_tree.nodes
    nodes.clear()
    out = nodes.new('ShaderNodeOutputMaterial')
    bsdf = nodes.new('ShaderNodeBsdfPrincipled')
    set_socket_val(bsdf, ['Base Color'], (0.012, 0.015, 0.020, 1.0))
    set_socket_val(bsdf, ['Roughness'], 0.85)
    mat_bg.node_tree.links.new(bsdf.outputs['BSDF'], out.inputs['Surface'])
    obj.data.materials.append(mat_bg)

# Setup Lights & Product Shot Camera
def setup_lighting_and_camera():
    # 1. Warm Core Point Light (Mantle Glow)
    light_data = bpy.data.lights.new(name="Mantle_Light", type='POINT')
    light_data.color = (1.0, 0.52, 0.12)
    light_data.energy = 38.0
    light_data.shadow_soft_size = 0.02
    light_obj = bpy.data.objects.new(name="Mantle_Light", object_data=light_data)
    light_obj.location = (0.0, 0.0, 0.183)
    bpy.context.collection.objects.link(light_obj)

    # 2. Cool Rim Light (Highlighting metallic silhouette against dark background)
    rim_data = bpy.data.lights.new(name="Rim_Light", type='AREA')
    rim_data.color = (0.22, 0.45, 0.85)
    rim_data.energy = 14.0
    rim_data.size = 0.6
    rim_obj = bpy.data.objects.new(name="Rim_Light", object_data=rim_data)
    rim_obj.location = (-0.75, 0.75, 0.65)

    # Point rim towards lantern
    dir_rim = mathutils.Vector((0, 0, 0.20)) - rim_obj.location
    rim_obj.rotation_euler = dir_rim.to_track_quat('-Z', 'Y').to_euler()
    bpy.context.collection.objects.link(rim_obj)

    # 3. Soft Front Fill Light (Subtle detail reveal)
    fill_data = bpy.data.lights.new(name="Fill_Light", type='AREA')
    fill_data.color = (0.8, 0.65, 0.5)
    fill_data.energy = 3.5
    fill_data.size = 0.8
    fill_obj = bpy.data.objects.new(name="Fill_Light", object_data=fill_data)
    fill_obj.location = (0.85, -0.65, 0.45)

    dir_fill = mathutils.Vector((0, 0, 0.18)) - fill_obj.location
    fill_obj.rotation_euler = dir_fill.to_track_quat('-Z', 'Y').to_euler()
    bpy.context.collection.objects.link(fill_obj)

    # 4. Hero Camera Setup
    cam_data = bpy.data.cameras.new(name="Product_Camera")
    cam_data.lens = 85
    cam_obj = bpy.data.objects.new(name="Product_Camera", object_data=cam_data)
    cam_obj.location = (0.60, -1.05, 0.36)

    # Track to target
    target = mathutils.Vector((0.0, 0.0, 0.185))
    direction = target - cam_obj.location
    cam_obj.rotation_euler = direction.to_track_quat('-Z', 'Y').to_euler()

    bpy.context.collection.objects.link(cam_obj)
    bpy.context.scene.camera = cam_obj

# Main Run Function
def main():
    setup_scene()
    mats = create_materials()
    build_lantern(mats)
    build_environment(mats)
    setup_lighting_and_camera()

if __name__ == "__main__":
    main()
```