import os

def load_valid_keys():
    valid = set()
    if os.path.exists('valid_keys.txt'):
        with open('valid_keys.txt', 'r') as f:
            for line in f:
                if line.strip():
                    valid.add(line.strip())
    # 补充一些在 PrusaSlicer ini常见但可能在cli中缺失的原生合法字段
    valid.update([
        "start_gcode", "end_gcode", "before_layer_gcode", "temperature",
        "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature",
        "printer_model", "family", "z_offset", "printer_technology",
        "gcode_flavor", "silent_mode", "printer_variant", "max_print_height",
        "nozzle_diameter", "extruder_colour", "extruder_offset", "use_relative_e_distances",
        "use_firmware_retraction", "retract_layer_change", "retract_length", 
        "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed",
        "deretract_speed", "retract_before_travel", "retract_before_wipe", "wipe",
        "machine_limits_usage", "machine_max_acceleration_x", "machine_max_acceleration_y",
        "machine_max_acceleration_z", "machine_max_acceleration_e",
        "machine_max_speed_x", "machine_max_speed_y", "machine_max_speed_z",
        "machine_max_speed_e", "machine_max_jerk_x", "machine_max_jerk_y",
        "machine_max_jerk_z", "machine_max_jerk_e", "machine_min_travel_rate",
        "default_filament_colour", "filament_type", "filament_diameter",
        "filament_density", "filament_cost", "fan_always_on", "cooling",
        "support_material", "support_material_auto", "support_material_style"
    ])
    return valid

VALID_KEYS = load_valid_keys()

# 基于全量 all_keys.txt 逐一梳理的语义映射字典
SEMANTIC_MAP = {
    # 打印层高相关
    "adaptive_layer_height": "variable_layer_height",
    "initial_layer_print_height": "first_layer_height",
    "layer_height": "layer_height",
    "min_layer_height": "min_layer_height",
    "max_layer_height": "max_layer_height",
    "print_sequence": "complete_objects",
    
    # 线宽相关
    "line_width": "extrusion_width",
    "initial_layer_line_width": "first_layer_extrusion_width",
    "outer_wall_line_width": "external_perimeter_extrusion_width",
    "inner_wall_line_width": "perimeter_extrusion_width",
    "top_surface_line_width": "top_infill_extrusion_width",
    "sparse_infill_line_width": "infill_extrusion_width",
    "internal_solid_infill_line_width": "solid_infill_extrusion_width",
    
    # 墙/外壳相关
    "wall_loops": "perimeters",
    "top_shell_layers": "top_solid_layers",
    "bottom_shell_layers": "bottom_solid_layers",
    "top_shell_thickness": "top_solid_min_thickness",
    "bottom_shell_thickness": "bottom_solid_min_thickness",
    "only_one_wall_top": "top_one_perimeter_type",
    "detect_thin_wall": "thin_walls",
    # "detect_narrow_internal_solid_infill": "thin_walls",
    "reduce_crossing_wall": "avoid_crossing_perimeters",
    
    # 填充相关
    "sparse_infill_density": "fill_density",
    "sparse_infill_pattern": "fill_pattern",
    "infill_direction": "fill_angle",
    "infill_wall_overlap": "infill_overlap",
    "infill_combination": "solid_infill_every_layers",
    "bottom_surface_pattern": "bottom_fill_pattern",
    "top_surface_pattern": "top_fill_pattern",
    "gap_fill_target": "gap_fill_enabled",
    
    # 速度相关
    "initial_layer_speed": "first_layer_speed",
    "initial_layer_infill_speed": "first_layer_infill_speed",
    "outer_wall_speed": "external_perimeter_speed",
    "inner_wall_speed": "perimeter_speed",
    "top_surface_speed": "top_solid_infill_speed",
    "sparse_infill_speed": "infill_speed",
    "internal_solid_infill_speed": "solid_infill_speed",
    "gap_infill_speed": "gap_fill_speed",
    "bridge_speed": "bridge_speed",
    "travel_speed": "travel_speed",
    "travel_speed_z": "travel_speed_z",
    "small_perimeter_speed": "small_perimeter_speed",
    "support_speed": "support_material_speed",
    "support_interface_speed": "support_material_interface_speed",
    
    # 加速度相关
    "default_acceleration": "default_acceleration",
    "initial_layer_acceleration": "first_layer_acceleration",
    "outer_wall_acceleration": "external_perimeter_acceleration",
    "inner_wall_acceleration": "perimeter_acceleration",
    "top_surface_acceleration": "top_solid_infill_acceleration",
    "travel_acceleration": "travel_acceleration",
    "bridge_acceleration": "bridge_acceleration",
    
    # 支撑相关
    "support_angle": "support_material_angle",
    "support_top_z_distance": "support_material_contact_distance",
    "support_bottom_z_distance": "support_material_bottom_contact_distance",
    "support_interface_top_layers": "support_material_interface_layers",
    "support_interface_bottom_layers": "support_material_bottom_interface_layers",
    "support_interface_spacing": "support_material_interface_spacing",
    # "support_remove_small_overhang": "support_material_threshold",
    "support_interface_pattern": "support_material_interface_pattern",
    
    # 底座/附着相关
    "brim_width": "brim_width",
    "raft_layers": "raft_layers",
    "raft_contact_distance": "raft_contact_distance",
    "raft_expansion": "raft_expansion",
    "raft_first_layer_density": "raft_first_layer_density",
    "raft_first_layer_expansion": "raft_first_layer_expansion",
    "skirt_distance": "skirt_distance",
    "skirt_height": "skirt_height",
    "skirt_loops": "skirts",
    "elefant_foot_compensation": "elefant_foot_compensation",
    
    # 回抽与耗材相关
    "z_hop": "retract_lift",
    "retract_length": "retract_length",
    "retract_speed": "retract_speed",
    "retract_before_wipe": "retract_before_wipe",
    "retract_before_travel": "retract_before_travel",
    "retract_layer_change": "retract_layer_change",
    "retract_lift_above": "retract_lift_above",
    "retract_lift_below": "retract_lift_below",
    "filament_deretraction_speed": "filament_deretract_speed",
    "filament_retraction_length": "filament_retract_length",
    "filament_retraction_speed": "filament_retract_speed",
    "material_type": "filament_type",
    "nozzle_temperature": "temperature",
    "nozzle_temperature_initial_layer": "first_layer_temperature",
    "filament_flow_ratio": "extrusion_multiplier",
    
    # 其他属性
    "bridge_flow": "bridge_flow_ratio",
    # "idle_temperature": "standby_temperature_delta",
    "enable_arc_fitting": "arc_fitting",
    "slowdown_for_curled_perimeters": "avoid_crossing_curled_overhangs",
    "slow_down_layer_time": "slowdown_below_layer_time",
    "fan_max_speed": "max_fan_speed",
    "fan_min_speed": "min_fan_speed",
    "spiral_mode": "spiral_vase",
    "prime_tower_brim_width": "wipe_tower_brim_width",
    "prime_tower_width": "wipe_tower_width",

    "bridge_no_support": "dont_support_bridges",
    "minimum_sparse_infill_area": "solid_infill_below_area",
    "xy_hole_compensation": "xy_size_compensation",
    "enable_prime_tower": "wipe_tower",
    "ironing_flow": "ironing_flowrate",
    "overhang_1_4_speed": "overhang_speed_0",
    "overhang_2_4_speed": "overhang_speed_1",
    "overhang_3_4_speed": "overhang_speed_2",
    "overhang_4_4_speed": "overhang_speed_3",
    "enable_overhang_speed": "enable_dynamic_overhang_speeds",
    "enforce_support_layers": "support_material_enforce_layers",
    "fuzzy_skin_point_distance": "fuzzy_skin_point_dist",
    # "initial_layer_min_bead_width": "min_bead_width",
    # "internal_bridge_flow": "bridge_flow_ratio",
    # "internal_bridge_speed": "bridge_speed",
    "internal_solid_infill_acceleration": "solid_infill_acceleration",
    "internal_solid_infill_pattern": "solid_fill_pattern",
    "is_infill_first": "infill_first",
    "seam_gap": "seam_gap_distance",
    "seam_slope_entire_loop": "scarf_seam_entire_loop",
    "seam_slope_inner_walls": "scarf_seam_on_inner_perimeters",
    "seam_slope_min_length": "scarf_seam_length",
    "seam_slope_start_height": "scarf_seam_start_height",
    "sparse_infill_acceleration": "infill_acceleration",
    "internal_solid_infill_acceleration": "solid_infill_acceleration",
    "wall_generator": "perimeter_generator",
    # "wipe_tower_rotation_angle": "wipe_tower_cone_angle"
}

def process_file(filepath):
    with open(filepath, 'r') as f:
        lines = f.readlines()
    
    new_lines = []
    changed = False
    
    for line in lines:
        stripped = line.strip()
        # 忽略空行、段名和已经是原生的配置行
        if not stripped or stripped.startswith('[') or stripped.startswith(';') or stripped.startswith('show_name'):
            new_lines.append(line)
            continue
            
        if '=' in line:
            parts = line.split('=', 1)
            raw_key = parts[0].strip()
            # 兼容前面可能被加了;;;的key重新解开的情况（以防跑多次）
            key = raw_key.lstrip(';') 
            val = parts[1].strip()
            
            # 处理一些特有的布尔值或字符串转义差异
            if key == "print_sequence" and val == "by layer":
                val = "0"
            elif key == "print_sequence" and val == "by object":
                val = "1"
            if key == "spiral_mode":
                val = "1" if val != "0" else "0"
            if key == "support_type" and "auto" in val:
                val = "1"

            if val == "zig-zag":
                val = "zigzag"

            if key == "enable_arc_fitting":
                if str(val) == "1":
                    val = "emit_center"
                else:
                    val = "disabled"
            
            if key == "only_one_wall_top":
                if str(val) == "1":
                    val = "top"
                else:
                    val = "none"

            if key in SEMANTIC_MAP:
                new_key = SEMANTIC_MAP[key]
                new_lines.append(f"{new_key} = {val}\n")
                changed = True
            elif key in VALID_KEYS:
                # 已经是PrusaSlicer的原生可用属性
                new_lines.append(f"{key} = {val}\n")
            else:
                # 在 all_keys.txt 中但找不到任何对应 PrusaSlicer 语义的属性
                new_lines.append(f";;;{raw_key} = {val}\n")
                changed = True
        else:
            new_lines.append(line)
            
    if changed:
        with open(filepath, 'w') as f:
            f.writelines(new_lines)
            
for root, dirs, files in os.walk('print_config/prusa_slicer'):
    for file in files:
        if file.endswith('.ini'):
            process_file(os.path.join(root, file))
print("All keys mapped exhaustively.")
