```python
import bpy
import math
import mathutils
from mathutils import Vector, Euler, Quaternion

# ===== Helpers =====

def clear_scene():
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)

def set_vertex_skin_radii(obj, radius_x, radius_y):
    """Set skin radius for all vertices in edit mode"""
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.transform.skin_resize(
        value=(radius_x, radius_y, 1),
        constraint_axis=(True, True, False),
        orient_type='LOCAL'
    )
    bpy.ops.object.mode_set(mode='OBJECT')

# ===== 1. Build boot skeleton with skin modifier =====

def create_boot_skeleton():
    # Define path: list of (x, y, z) points, y=0 centreline
    path = []
    z_ankle_top = 1.5
    z_sole = 0.08
    # Ankle region
    for i in range(5):
        t = i / 4.0
        z = z_ankle_top - t * 0.5  # 1.5 -> 1.0
        path.append(Vector((0.0, 0.0, z)))
    # Heel and foot transition
    path.append(Vector((-0.05, 0.0, 0.6)))
    path.append(Vector((-0.10, 0.0, 0.4)))
    path.append(Vector((-0.12, 0.0, 0.2)))
    path.append(Vector((-0.10, 0.0, z_sole)))  # heel
    # Arch and forefoot
    path.append(Vector((0.05, 0.0, z_sole)))
    path.append(Vector((0.15, 0.0, z_sole)))
    path.append(Vector((0.30, 0.0, z_sole)))
    path.append(Vector((0.45, 0.0, z_sole)))
    path.append(Vector((0.60, 0.0, z_sole)))
    path.append(Vector((0.75, 0.0, z_sole)))
    path.append(Vector((0.85, 0.0, z_sole)))  # toe tip

    # Create mesh with vertices and edges
    mesh = bpy.data.meshes.new("BootSkeleton")
    obj = bpy.data.objects.new("BootSkeleton", mesh)
    bpy.context.collection.objects.link(obj)

    verts = path
    edges = [(i, i+1) for i in range(len(verts)-1)]
    mesh.from_pydata(verts, edges, [])
    mesh.update()

    # Add skin modifier
    skin = obj.modifiers.new('Skin', 'SKIN')
    skin.use_smooth_shade = True

    # Set skin radii (approx boot shape)
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    # radii: (X_lateral, Y_vertical) but skin uses local axes; we'll tweak
    # Use transform to set roughly
    bpy.ops.transform.skin_resize(
        value=(0.14, 0.14, 1),
        constraint_axis=(True, True, False),
        orient_type='LOCAL'
    )
    bpy.ops.object.mode_set(mode='OBJECT')

    # Adjust radii per vertex manually via vertex layer
    # We'll set 'skin_radius' data
    bpy.ops.object.mode_set(mode='OBJECT')
    obj.data.use_auto_smooth = True
    # Get skin layer
    skin_data = obj.data.skin_vertices[0].data if obj.data.skin_vertices else None
    if skin_data is None:
        # Force creation by toggling edit mode
        bpy.ops.object.mode_set(mode='EDIT')
        bpy.ops.object.mode_set(mode='OBJECT')
        skin_data = obj.data.skin_vertices[0].data

    # Define custom radii per vertex based on position
    for i, skin_vert in enumerate(skin_data):
        pos = verts[i]
        z = pos.z
        x = pos.x
        # Heel region: wide and tall? Actually boot heel is narrower
        if x < -0.05:
            width = 0.10
            height = 0.12
        elif x < 0.2:
            # Arch: narrower
            width = 0.09
            height = 0.10
        else:
            # Forefoot: wider, flatter
            width = 0.18
            height = 0.08
        # adjust for ankle top: smaller
        if z > 1.2:
            width = 0.10
            height = 0.10
        elif z > 0.8:
            width = 0.11
            height = 0.11
        skin_vert.radius[0] = width
        skin_vert.radius[1] = height

    # Add subdivision modifier
    subdiv = obj.modifiers.new('Subdivision', 'SUBSURF')
    subdiv.levels = 2
    subdiv.render_levels = 2

    return obj

# ===== 2. Add sole =====

def add_sole(boot_obj):
    # Duplicate boot bottom faces, separate, thicken
    bpy.context.view_layer.objects.active = boot_obj
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='DESELECT')
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select vertices at bottom (lowest Z) - approximate
    # We'll use a different method: create sole shape manually
    # Use curve to trace footprint, then extrude

    # Create a flat footprint shape using a curve
    bpy.ops.curve.primitive_bezier_circle_add(
        location=(0.35, 0, 0.04),
        rotation=(0, 0, 0),
        scale=(0.35, 0.15, 0.15)
    )
    sole_curve = bpy.context.object
    sole_curve.data.resolution_u = 12
    # Convert to mesh
    bpy.ops.object.convert(target='MESH')
    sole_mesh = bpy.context.object
    sole_mesh.name = "Sole"

    # Extrude downward for thickness
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.mesh.extrude_region_move(
        TRANSFORM_OT_translate={"value": (0, 0, -0.15)}
    )
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.mesh.normals_make_consistent(inside=False)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Make it slightly larger to overlap boot
    sole_mesh.scale = (1.0, 1.0, 1.0)
    # Slightly offset in Y to simulate asymmetry? not needed yet

    # Add edge split for sharp sole edge? no

    # Add subdivision
    sole_mesh.modifiers.new('Subdivision', 'SUBSURF')
    sole_mesh.modifiers['Subdivision'].levels = 1

    return sole_mesh

# ===== 3. Add heel block =====

def add_heel(sole_obj):
    # Create a box for heel under the sole heel area
    bpy.ops.mesh.primitive_cube_add(
        location=(-0.10, 0, -0.08),
        scale=(0.10, 0.08, 0.12)
    )
    heel = bpy.context.object
    heel.name = "HeelBlock"
    # Round edges
    mod = heel.modifiers.new('Bevel', 'BEVEL')
    mod.width = 0.03
    mod.segments = 3
    mod.limit_method = 'ANGLE'
    mod.angle_limit = 0.5
    bpy.ops.object.modifier_apply(modifier=mod.name)

    return heel

# ===== 4. Add tongue =====

def add_tongue(boot_obj):
    # Create a curved sheet from front opening
    # We'll make a mesh from two arcs
    bpy.ops.mesh.primitive_grid_add(
        size=0.1,
        x_subdivisions=2,
        y_subdivisions=4,
        location=(0.05, 0, 0.45)
    )
    tongue = bpy.context.object
    tongue.name = "Tongue"
    # Edit to shape
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.transform.resize(value=(0.12, 0.05, 0.15))
    # Move vertices to position
    # Simulate curve
    bpy.ops.object.mode_set(mode='OBJECT')
    # Apply rotation to align
    tongue.rotation_euler = (0.2, 0, 0)
    # Add subdivision
    tongue.modifiers.new('Subdivision', 'SUBSURF')
    tongue.modifiers['Subdivision'].levels = 2
    return tongue

# ===== 5. Add collar padding =====

def add_collar(boot_obj):
    # Use a torus around top edge
    bpy.ops.mesh.primitive_torus_add(
        location=(0.0, 0.0, 1.4),
        rotation=(1.5708, 0, 0),
        major_radius=0.1,
        minor_radius=0.025,
        major_segments=12,
        minor_segments=4
    )
    collar = bpy.context.object
    collar.name = "Collar"
    # Scale to fit boot top
    collar.scale = (1.5, 1.0, 1.0)
    # Flatten bottom
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.mesh.extrude_region_move(
        TRANSFORM_OT_translate={"value": (0, 0, -0.03)}
    )
    bpy.ops.object.mode_set(mode='OBJECT')
    return collar

# ===== 6. Add eyelets and laces =====

def add_eyelets(boot_obj):
    # Place eyelets along two vertical rows on front upper
    # Row positions: left and right
    eyelets = []
    for side in [-1, 1]:
        for i in range(6):
            y = side * 0.08
            z = 0.3 + i * 0.15
            x = 0.02  # slight forward lean
            # Create an eyelet ring
            bpy.ops.mesh.primitive_torus_add(
                location=(x, y, z),
                rotation=(1.5708, 0, 0),
                major_radius=0.025,
                minor_radius=0.008,
                major_segments=8,
                minor_segments=4
            )
            eyelet = bpy.context.object
            eyelet.name = f"Eyelet_{side}_{i}"
            eyelets.append(eyelet)
    return eyelets

def add_lace(eyelets):
    # Create a curve with round bevel threaded through eyelets
    # Define points along a path that weaves
    points = []
    # Sort eyelets by z
    # We'll manually create a simple lace pattern
    # For demo, do straight segments between eyelets
    # Place laces as separate curve for each crisscross segment
    # Not fully implemented due to complexity
    pass

# ===== 7. Add welt and stitching =====

def add_welt(boot_obj, sole_obj):
    # A thin loop around sole edge - use curve
    # We'll use a bezier circle around sole perimeter
    bpy.ops.curve.primitive_bezier_circle_add(
        location=(0.35, 0, 0.04),
        rotation=(0, 0, 0),
        scale=(0.38, 0.18, 0.18)
    )
    welt_curve = bpy.context.object
    welt_curve.name = "Welt"
    welt_curve.data.resolution_u = 16
    # Convert to mesh, extrude vertically
    bpy.ops.object.convert(target='MESH')
    welt_mesh = bpy.context.object
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.mesh.extrude_region_move(
        TRANSFORM_OT_translate={"value": (0, 0, 0.02)}
    )
    bpy.ops.object.mode_set(mode='OBJECT')
    # Add stitch dots: use array of small spheres? We'll skip complex stitch
    return welt_mesh

# ===== 8. Add heel-pull loop =====

def add_heel_pull(boot_obj):
    # Small loop at back of collar
    bpy.ops.mesh.primitive_torus_add(
        location=(-0.12, 0, 1.2),
        rotation=(0, 0, 0),
        major_radius=0.03,
        minor_radius=0.01,
        major_segments=6,
        minor_segments=3
    )
    pull = bpy.context.object
    pull.name = "HeelPull"
    return pull

# ===== 9. Add asymmetry and creases =====

def add_wear_and_tear(boot_obj):
    # Move vertices to create creases, collapsed leather, slouch
    bpy.context.view_layer.objects.active = boot_obj
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='DESELECT')
    # Select front toe area and shift slightly down and back
    # We'll do a quick lattice distortion later
    bpy.ops.object.mode_set(mode='OBJECT')

    # Add lattice modifier for overall slump
    lattice = boot_obj.modifiers.new('Lattice', 'LATTICE')
    lat_obj = bpy.data.objects.new('BootLattice', bpy.data.lattices.new('BootLattice'))
    bpy.context.collection.objects.link(lat_obj)
    lat_obj.scale = (1, 1, 1)
    lattice.object = lat_obj

    # Deform lattice vertices to create slump
    # Not implemented fully - but we can randomize lattice points
    import random
    random.seed(0)
    lat = lat_obj.data
    lat.points_u = 4
    lat.points_v = 4
    lat.points_w = 4
    # Randomize Z positions slightly
    for point in lat.points:
        point.co_deform[2] += random.uniform(-0.02, 0.02)
    # Also twist slightly
    for i, point in enumerate(lat.points):
        x = point.co_deform[0]
        z = point.co_deform[2]
        if z > 0.5:
            point.co_deform[0] += 0.01 * (z - 0.5)
    bpy.ops.object.mode_set(mode='OBJECT')

# ===== 10. Materials =====

def create_leather_material():
    mat = bpy.data.materials.new('Leather')
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    nodes.clear()

    # Principled BSDF
    principled = nodes.new('ShaderNodeBsdfPrincipled')
    principled.inputs['Base Color'].default_value = (0.25, 0.15, 0.08, 1)
    principled.inputs['Roughness'].default_value = 0.6
    principled.inputs['Specular'].default_value = 0.5
    principled.location = (0, 0)

    # Bump for grain
    tex_coord = nodes.new('ShaderNodeTexCoord')
    mapping = nodes.new('ShaderNodeMapping')
    noise = nodes.new('ShaderNodeTexNoise')
    noise.inputs['Scale'].default_value = 100
    noise.inputs['Detail'].default_value = 10
    noise.inputs['Roughness'].default_value = 0.5
    bump = nodes.new('ShaderNodeBump')
    bump.inputs['Strength'].default_value = 0.3
    links.new(tex_coord.outputs['UV'], mapping.inputs['Vector'])
    links.new(mapping.outputs['Vector'], noise.inputs['Vector'])
    links.new(noise.outputs['Fac'], bump.inputs['Height'])
    links.new(bump.outputs['Normal'], principled.inputs['Normal'])

    # Color variation (creases, burnishing)
    color_ramp = nodes.new('ShaderNodeValToRGB')
    color_ramp.color_ramp.elements[0].color = (0.35, 0.20, 0.10, 1)
    color_ramp.color_ramp.elements[1].color = (0.20, 0.12, 0.05, 1)
    # Use another noise for burnish mask
    noise2 = nodes.new('ShaderNodeTexNoise')
    noise2.inputs['Scale'].default_value = 20
    noise2.inputs['Detail'].default_value = 3
    links.new(mapping.outputs['Vector'], noise2.inputs['Vector'])
    links.new(noise2.outputs['Fac'], color_ramp.inputs['Fac'])
    mix = nodes.new('ShaderNodeMixRGB')
    mix.inputs['Fac'].default_value = 0.2
    links.new(color_ramp.outputs['Color'], mix.inputs[1])
    links.new(principled.inputs['Base Color'], mix.inputs[2])
    # This is messy; skip for time

    # Output
    output = nodes.new('ShaderNodeOutputMaterial')
    links.new(principled.outputs['BSDF'], output.inputs['Surface'])

    return mat

def create_metal_eyelets_material():
    mat = bpy.data.materials.new('MetalEyelet')
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    nodes.clear()
    principled = nodes.new('ShaderNodeBsdfPrincipled')
    principled.inputs['Base Color'].default_value = (0.8, 0.7, 0.5, 1)
    principled.inputs['Roughness'].default_value = 0.3
    principled.inputs['Metallic'].default_value = 0.9
    output = nodes.new('ShaderNodeOutputMaterial')
    links.new(principled.outputs['BSDF'], output.inputs['Surface'])
    return mat

def create_sole_material():
    mat = bpy.data.materials.new('SoleRubber')
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    nodes.clear()
    principled = nodes.new('ShaderNodeBsdfPrincipled')
    principled.inputs['Base Color'].default_value = (0.1, 0.1, 0.1, 1)
    principled.inputs['Roughness'].default_value = 0.9
    output = nodes.new('ShaderNodeOutputMaterial')
    links.new(principled.outputs['BSDF'], output.inputs['Surface'])
    return mat

# ===== 11. Lighting and camera =====

def setup_scene():
    # Clear scene
    clear_scene()

    # Create floor (studio sweep)
    bpy.ops.mesh.primitive_plane_add(size=5, location=(0.5, 0, -0.1))
    floor = bpy.context.object
    floor.name = "Sweep"
    # Add a curved back? Use a simple plane, make it large

    # Camera
    bpy.ops.object.camera_add(
        location=(0.6, -0.4, 0.5),
        rotation=(1.2, 0, 0.4)
    )
    cam = bpy.context.object
    cam.name = "BoothCam"
    cam.data.lens = 85
    bpy.context.scene.camera = cam

    # Lights
    # Key light - large area soft
    bpy.ops.object.light_add(
        type='AREA',
        location=(0.2, -0.8, 1.0),
        rotation=(0.8, 0.2, 0.5),
        energy=200
    )
    key = bpy.context.object
    key.name = "KeyLight"
    key.data.size = 1.0

    # Fill light
    bpy.ops.object.light_add(
        type='AREA',
        location=(-0.3, 0.6, 0.4),
        rotation=(-1.2, 0, 0.5),
        energy=50
    )
    fill = bpy.context.object
    fill.name = "FillLight"
    fill.data.size = 0.8

    # Rim light
    bpy.ops.object.light_add(
        type='AREA',
        location=(0.8, 0.5, 0.3),
        rotation=(-1.0, 0, -1.0),
        energy=100
    )
    rim = bpy.context.object
    rim.name = "RimLight"
    rim.data.size = 0.5

    return cam

# ===== Main =====

def main():
    # Setup scene
    setup_scene()

    # Build boot
    boot_obj = create_boot_skeleton()

    # Add sole
    sole_obj = add_sole(boot_obj)

    # Add heel
    heel_obj = add_heel(sole_obj)

    # Join sole + heel to boot? For simplicity keep separate

    # Add tongue
    tongue_obj = add_tongue(boot_obj)

    # Add collar
    collar_obj = add_collar(boot_obj)

    # Add eyelets
    eyelets = add_eyelets(boot_obj)

    # Add welt
    welt_obj = add_welt(boot_obj, sole_obj)

    # Add heel pull
    pull_obj = add_heel_pull(boot_obj)

    # Add wear
    add_wear_and_tear(boot_obj)

    # Parent all to boot? Not necessary

    # Materials
    leather_mat = create_leather_material()
    boot_obj.data.materials.append(leather_mat)
    tongue_obj.data.materials.append(leather_mat)
    collar_obj.data.materials.append(leather_mat)

    metal_mat = create_metal_eyelets_material()
    for e in eyelets:
        e.data.materials.append(metal_mat)

    sole_mat = create_sole_material()
    sole_obj.data.materials.append(sole_mat)
    heel_obj.data.materials.append(sole_mat)
    welt_obj.data.materials.append(sole_mat)

    # Set render engine to Cycles
    bpy.context.scene.render.engine = 'CYCLES'
    bpy.context.scene.render.resolution_x = 1536
    bpy.context.scene.render.resolution_y = 1536

    # Save blend file as instructed? Not required but we can save

    # Ensure smooth shading on boot
    bpy.context.view_layer.objects.active = boot_obj
    bpy.ops.object.shade_smooth()

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