import os
import re
from ortools.sat.python import cp_model

def solve_bin_packing(item_sizes, bin_capacity):
    """使用 OR-Tools CP-SAT 解决 BPP 问题 (逻辑保持不变)"""
    num_items = len(item_sizes)
    num_bins = num_items

    model = cp_model.CpModel()

    x = {}
    for i in range(num_items):
        for j in range(num_bins):
            x[i, j] = model.NewBoolVar(f"x_{i}_{j}")

    y = [model.NewBoolVar(f"y_{j}") for j in range(num_bins)]

    for i in range(num_items):
        model.Add(sum(x[i, j] for j in range(num_bins)) == 1)

    for j in range(num_bins):
        model.Add(sum(item_sizes[i] * x[i, j] for i in range(num_items)) <= bin_capacity * y[j])

    model.Minimize(sum(y[j] for j in range(num_bins)))

    solver = cp_model.CpSolver()
    solver.parameters.max_time_in_seconds = 60.0
    status = solver.Solve(model)

    if status in [cp_model.OPTIMAL, cp_model.FEASIBLE]:
        used_bins = []
        for j in range(num_bins):
            if solver.Value(y[j]) == 1:
                bin_items = [i for i in range(num_items) if solver.Value(x[i, j]) == 1]
                used_bins.append(bin_items)
        return used_bins
    else:
        return None


def extract_capacity_from_filename(filename):
    """从文件名中提取第二个数字作为容量 (逻辑保持不变)"""
    numbers = re.findall(r"\d+", filename)
    if len(numbers) >= 2:
        return int(numbers[1])
    else:
        raise ValueError(f"文件名 '{filename}' 不符合预期的格式 (至少需要包含两个数字).")


def process_folder(input_folder):
    """
    遍历文件夹中的 txt 文件，解决 BPP 问题。
    - 如果成功，将结果追加到原文件末尾。
    - 如果失败或无解，删除原文件。
    """
    filenames = [f for f in os.listdir(input_folder) if f.endswith(".txt")]

    for filename in filenames:
        filepath = os.path.join(input_folder, filename)
        
        try:
            print(f"正在处理文件: {filename}")
            
            # 1. 提取容量
            bin_capacity = extract_capacity_from_filename(filename)

            # 2. 读取数据
            with open(filepath, "r", encoding='utf-8') as f:
                lines = f.readlines()
                # 检查文件是否已经包含解决方案，如果包含则跳过
                if any("=== Bin Packing Solution" in line for line in lines):
                    print(f"  -> 文件 '{filename}' 已包含求解结果，跳过处理。")
                    continue
                
                item_sizes = [int(line.strip()) for line in lines if line.strip().isdigit()]
            
            if not item_sizes:
                raise ValueError("文件中不包含有效的物品尺寸数据。")

            # 3. 求解
            solution = solve_bin_packing(item_sizes, bin_capacity)

            # 4. 根据结果处理文件
            if solution is None:
                # 如果找不到解，抛出异常，由 except 块统一处理删除
                raise ValueError("求解器未在规定时间内找到可行解。")
            else:
                # 【关键修改】如果找到解，以追加模式('a')打开文件，在末尾添加结果
                with open(filepath, "a", encoding='utf-8') as f:
                    f.write("\n\n=== Bin Packing Solution (OR-Tools) ===\n")
                    f.write(f"Bin Capacity: {bin_capacity}\n")
                    f.write(f"Total Bins Used: {len(solution)}\n")
                    f.write("=" * 40 + "\n")
                    for idx, bin_items in enumerate(solution, 1):
                        total_size = sum(item_sizes[i] for i in bin_items)
                        item_details = ", ".join(str(item_sizes[i]) for i in bin_items)
                        f.write(f"Bin {idx} (Items: {len(bin_items)}, Sum: {total_size}/{bin_capacity}): {item_details}\n")
                print(f"  -> 处理完成 '{filename}', 结果已追加。使用的箱子数: {len(solution)}")

        except Exception as e:
            # 如果处理过程中发生任何错误，打印错误信息并删除文件
            print(f"  -> 处理文件 '{filename}' 时发生错误，文件将被删除。")
            print(f"     错误详情: {e}")
            if os.path.exists(filepath):
                os.remove(filepath)


if __name__ == "__main__":
    # 再次确认：请确保这里的路径是您存放 txt 文件的正确目录
    # ！！！运行前请务必备份此文件夹 ！！！
    input_folder = "/home/liuyihong/openevolve/examples/BPP/base_input"
    process_folder(input_folder)
    print("\n所有文件处理完毕。")