# Use the existing connected PyFluent variable solver.
# Continue with the complete executable script here.

task_directory = r"C:\Users\13977\AppData\Local\FluentAGI\data\runs\20261020-133519-b9bc11"
case_directory = task_directory + r"\vertical-water-jet-demo"
backup_path = task_directory + r"\before-vertical-water-jet.cas.h5"

tank_width = 0.04
tank_height = 0.06
tank_depth = 0.04
nozzle_radius = 0.006
inlet_velocity = 1.0
time_step = 0.0005
frames = 45
steps_per_frame = 8
max_iter_per_step = 20

results = []

def show(label, value):
    print("\n--- " + label + " ---")
    print(repr(value))

def has_failure(obj):
    if isinstance(obj, dict):
        if obj.get("needs_review") is True:
            return True
        if obj.get("errors"):
            return True
        for key in ("status", "run_status"):
            if str(obj.get(key, "")).lower() in (
                "failed", "error", "aborted", "needs_review"
            ):
                return True
        for value in obj.values():
            if has_failure(value):
                return True
    elif isinstance(obj, (list, tuple)):
        for value in obj:
            if has_failure(value):
                return True
    return False

def find_value(obj, wanted_key):
    if isinstance(obj, dict):
        if wanted_key in obj and obj[wanted_key] is not None:
            return obj[wanted_key]
        for value in obj.values():
            found = find_value(value, wanted_key)
            if found is not None:
                return found
    elif isinstance(obj, (list, tuple)):
        for value in obj:
            found = find_value(value, wanted_key)
            if found is not None:
                return found
    return None

def find_gifs(obj):
    paths = []
    if isinstance(obj, str):
        if obj.lower().endswith(".gif"):
            paths.append(obj)
    elif isinstance(obj, dict):
        for value in obj.values():
            paths.extend(find_gifs(value))
    elif isinstance(obj, (list, tuple)):
        for value in obj:
            paths.extend(find_gifs(value))
    return paths

def water_is_phase2(obj):
    if isinstance(obj, dict):
        identity = " ".join(
            str(obj.get(key, ""))
            for key in ("phase", "name", "tag", "phase_name")
        ).lower().replace("_", "-")
        material = " ".join(
            str(obj.get(key, ""))
            for key in ("material", "material_name", "assigned_material")
        ).lower()

        if "phase-2" in identity and "water-liquid" in material:
            return True

        for key, value in obj.items():
            normalized = str(key).lower().replace("_", "-")
            if (
                "phase-2" in normalized
                and "water-liquid" in str(value).lower()
            ):
                return True
            if water_is_phase2(value):
                return True

    elif isinstance(obj, (list, tuple)):
        for value in obj:
            if water_is_phase2(value):
                return True

    return False

def main():
    print("=== 三维立式水箱底部喷射动画 ===")
    print("任务目录:", task_directory)
    print("独立算例:", case_directory)
    print("保留现有算例备份；不重放旧的失败计算。")

    if not solver.is_active():
        print("当前求解器不活跃，停止操作。")
        return

    # 1. 备份当前活动算例，之后才允许切换网格。
    try:
        backup = solver.settings.file.write_case_data(
            file_name=backup_path
        )
        show("当前 Case/Data 备份", backup)
    except Exception as exc:
        print("备份失败，停止操作:", repr(exc))
        return

    # 2. 使用 OCC 构建水箱与底部喷嘴连通的三维流体域。
    #    喷嘴入口位于 Y=-0.02 m，水箱顶部出口位于 Y=0.06 m。
    gmsh_code = """
gmsh.model.add("vertical_water_jet")

tank = gmsh.model.occ.addBox(
    -0.02, 0.0, -0.02,
    0.04, 0.06, 0.04
)

nozzle = gmsh.model.occ.addCylinder(
    0.0, -0.02, 0.0,
    0.0, 0.022, 0.0,
    0.006
)

fused, mapping = gmsh.model.occ.fuse(
    [(3, tank)], [(3, nozzle)],
    removeObject=True, removeTool=True
)
gmsh.model.occ.synchronize()

volumes = [tag for dim, tag in fused if dim == 3]
if not volumes:
    raise RuntimeError("水箱与喷嘴未生成有效连通体积")

inlet_tags = []
outlet_tags = []
wall_tags = []

for dim, tag in gmsh.model.getEntities(2):
    xmin, ymin, zmin, xmax, ymax, zmax = (
        gmsh.model.getBoundingBox(dim, tag)
    )
    if abs(ymin + 0.02) < 1e-6 and abs(ymax + 0.02) < 1e-6:
        inlet_tags.append(tag)
    elif abs(ymin - 0.06) < 1e-6 and abs(ymax - 0.06) < 1e-6:
        outlet_tags.append(tag)
    else:
        wall_tags.append(tag)

if not inlet_tags or not outlet_tags or not wall_tags:
    raise RuntimeError(
        "无法识别完整的入口、出口和壁面，停止生成网格"
    )

fluid_group = gmsh.model.addPhysicalGroup(3, volumes)
gmsh.model.setPhysicalName(3, fluid_group, "fluid")

inlet_group = gmsh.model.addPhysicalGroup(2, inlet_tags)
gmsh.model.setPhysicalName(2, inlet_group, "inlet")

outlet_group = gmsh.model.addPhysicalGroup(2, outlet_tags)
gmsh.model.setPhysicalName(2, outlet_group, "outlet")

wall_group = gmsh.model.addPhysicalGroup(2, wall_tags)
gmsh.model.setPhysicalName(2, wall_group, "walls")

gmsh.option.setNumber("Mesh.ElementOrder", 1)
gmsh.option.setNumber("Mesh.Algorithm3D", 1)
gmsh.option.setNumber("Mesh.MeshSizeMin", 0.0018)
gmsh.option.setNumber("Mesh.MeshSizeMax", 0.0035)
gmsh.model.mesh.setSize(gmsh.model.getEntities(0), 0.0035)

# 在喷嘴附近进一步细化几何顶点处的网格尺寸。
for dim, tag in gmsh.model.getEntities(0):
    x, y, z = gmsh.model.occ.getCenterOfMass(dim, tag)
    if (
        -0.021 <= y <= 0.012
        and abs(x) <= 0.009
        and abs(z) <= 0.009
    ):
        gmsh.model.mesh.setSize([(0, tag)], 0.0018)

gmsh.model.mesh.generate(3)
"""

    try:
        mesh_result = fluentagi.geometry_mesh(
            directory=case_directory,
            code=gmsh_code
        )
        show("三维 CAD 与网格生成", mesh_result)
        results.append(mesh_result)
    except Exception as exc:
        print("几何或网格生成异常:", repr(exc))
        return

    if has_failure(mesh_result):
        print("网格结果包含错误，停止切换求解器网格。")
        return

    mesh_file = find_value(mesh_result, "mesh_file")
    if not mesh_file:
        print("没有取得明确的 Fluent 网格文件路径，停止。")
        return

    # 3. 读取新网格并检查。
    try:
        read_result = solver.settings.file.read_mesh(
            file_name=mesh_file
        )
        show("读取 Fluent 网格", read_result)

        check_result = solver.settings.mesh.check()
        show("网格质量检查", check_result)
        results.extend([read_result, check_result])
    except Exception as exc:
        print("网格读取或检查失败:", repr(exc))
        return

    if has_failure(check_result):
        print("网格检查返回错误，停止物理设置。")
        return

    # 4. 配置水-空气瞬态 VOF、入口、出口和重力。
    try:
        physics = fluentagi.configure_water_air(
            directory=case_directory,
            velocity=inlet_velocity,
            time_step=time_step,
            gravity_y=-9.81,
            inlet="inlet",
            outlet="outlet"
        )
        show("水-空气 VOF 物理设置", physics)
        results.append(physics)
    except Exception as exc:
        print("VOF 配置失败:", repr(exc))
        return

    if has_failure(physics):
        print("物理设置需要复核，停止。")
        return

    # 5. 显式设置材料映射，并核实第二相确实为液态水。
    try:
        phase_setup = fluentagi.assign_phase_materials(
            primary="air",
            secondary="water-liquid",
            directory=case_directory
        )
        show("气液相材料映射", phase_setup)
        results.append(phase_setup)

        phase_state = fluentagi.inspect_phases()
        show("原生相状态核验", phase_state)
        results.append(phase_state)
    except Exception as exc:
        print("相状态检查失败，停止初始化:", repr(exc))
        return

    if not water_is_phase2(phase_state):
        print("未能确认 phase-2=water-liquid，停止初始化。")
        return

    # 6. 设置水-空气表面张力并读取回读状态。
    try:
        tension = fluentagi.configure_surface_tension(
            directory=case_directory,
            coefficient=0.072,
            phase_a="phase-1",
            phase_b="phase-2"
        )
        show("表面张力设置", tension)
        results.append(tension)

        tension_state = fluentagi.inspect_surface_tension(
            directory=case_directory
        )
        show("表面张力原生回读", tension_state)
        results.append(tension_state)
    except Exception as exc:
        print("表面张力配置失败:", repr(exc))
        return

    if has_failure(tension):
        print("表面张力配置异常，停止初始化。")
        return

    # 7. 这是全新网格上的新算例，只初始化本算例一次。
    try:
        init_result = fluentagi.initialize_air(
            directory=case_directory
        )
        show("新算例初始化", init_result)
        results.append(init_result)
    except Exception as exc:
        print("初始化异常，不自动重试:", repr(exc))
        return

    if has_failure(init_result):
        print("初始化状态异常，停止动画推进。")
        return

    # 8. 建立 Z=0 中截面，显示真实水相体积分数。
    try:
        section = fluentagi.create_section(
            axis="z",
            position=0.0
        )
        show("水箱内部截面", section)
    except Exception as exc:
        print("截面创建失败:", repr(exc))
        return

    surface = find_value(section, "surface")
    if not surface:
        print("没有取得有效截面名称，停止动画。")
        return

    # 9. 生成水相体积分数动画；这一步会真实推进求解。
    animation = None
    try:
        animation = fluentagi.record_animation(
            directory=case_directory,
            field="phase-2-vof",
            frames=frames,
            steps_per_frame=steps_per_frame,
            max_iter_per_step=max_iter_per_step,
            surfaces=[surface]
        )
        show("瞬态水柱动画", animation)
        results.append(animation)
    except Exception as exc:
        print("动画推进或导出异常，不盲目重试:", repr(exc))

    # 10. 导出当前截面压力和速度，不额外推进计算。
    try:
        export_result = fluentagi.export_results(
            directory=case_directory,
            fields=["pressure", "velocity-magnitude"],
            surfaces=[surface]
        )
        show("截面压力和速度结果", export_result)
        results.append(export_result)
    except Exception as exc:
        print("后处理导出异常:", repr(exc))

    # 11. 只报告实际返回的 GIF 路径与导出状态。
    gif_paths = list(dict.fromkeys(find_gifs(results)))
    print("\n=== 最终核验 ===")
    print("算例目录:", case_directory)
    print("目标动画帧数:", frames)
    print("每帧推进步数:", steps_per_frame)
    print("时间步长:", time_step)
    print(
        "计划动画时间跨度:",
        (frames - 1) * steps_per_frame * time_step,
        "s"
    )
    print("实际返回的 GIF 路径:", gif_paths)
    print("动画返回结果:", repr(animation))
    print("动画是否存在明确错误:", has_failure(animation))
    print("网格尺寸、收敛性和水量守恒仍需根据原生结果核验。")
    print("当前截面是三维水箱的 Z 中截面，不是完整体渲染。")

    if not gif_paths:
        print("尚未取得明确的 GIF 文件路径，不宣称动画文件已成功导出。")

main()