# Use the existing connected PyFluent variable solver.
task_directory = r"C:\Users\13977\AppData\Local\FluentAGI\data\runs\20261018-000431-40ac88"
prefix = task_directory + "/cylinder_re100_a9e438cc"
settings = solver.settings

if settings.setup.models.is_active():
    settings.file.write_case_data(file_name=prefix + "_previous.cas.h5")

gmsh_code = """
gmsh.model.add("cylinder_re100")
occ = gmsh.model.occ
rectangle = occ.addRectangle(0, 0, 0, 2.2, 0.41)
disk = occ.addDisk(0.2, 0.2, 0, 0.05, 0.05)
fluid, mapping = occ.cut([(2, rectangle)], [(2, disk)])
occ.synchronize()
surfaces = [tag for dim, tag in fluid if dim == 2]
if len(surfaces) != 1:
    raise RuntimeError("Expected one connected fluid surface")
boundary = gmsh.model.getBoundary(fluid, oriented=False)
groups = {"inlet": [], "outlet": [], "walls": []}
cylinder = []
for dim, tag in boundary:
    x, y, z = occ.getCenterOfMass(dim, tag)
    if abs(x) < 1e-7:
        groups["inlet"].append(tag)
    elif abs(x - 2.2) < 1e-7:
        groups["outlet"].append(tag)
    else:
        groups["walls"].append(tag)
        if abs(x - 0.2) < 0.06 and abs(y - 0.2) < 0.06:
            cylinder.append(tag)
if not cylinder:
    raise RuntimeError("Cylinder boundary identification failed")
for name, tags in groups.items():
    if not tags:
        raise RuntimeError("Missing boundary: " + name)
    group = gmsh.model.addPhysicalGroup(1, tags)
    gmsh.model.setPhysicalName(1, group, name)
group = gmsh.model.addPhysicalGroup(2, surfaces)
gmsh.model.setPhysicalName(2, group, "fluid")
field = gmsh.model.mesh.field
distance = field.add("Distance")
field.setNumbers(distance, "CurvesList", cylinder)
field.setNumber(distance, "Sampling", 120)
near = field.add("Threshold")
for key, value in [
    ("InField", distance), ("SizeMin", 0.004),
    ("SizeMax", 0.03), ("DistMin", 0.015), ("DistMax", 0.15)
]:
    field.setNumber(near, key, value)
wake = field.add("Box")
for key, value in [
    ("VIn", 0.012), ("VOut", 0.03),
    ("XMin", 0.2), ("XMax", 1.9),
    ("YMin", 0.09), ("YMax", 0.31),
    ("ZMin", -0.01), ("ZMax", 0.01), ("Thickness", 0.04)
]:
    field.setNumber(wake, key, value)
minimum = field.add("Min")
field.setNumbers(minimum, "FieldsList", [near, wake])
field.setAsBackgroundMesh(minimum)
for key, value in [
    ("Mesh.MeshSizeExtendFromBoundary", 0),
    ("Mesh.MeshSizeFromPoints", 0),
    ("Mesh.MeshSizeFromCurvature", 0),
    ("Mesh.ElementOrder", 1),
    ("Mesh.Algorithm", 6)
]:
    gmsh.option.setNumber(key, value)
gmsh.write(output_dir + "/cylinder.step")
gmsh.model.mesh.generate(2)
gmsh.model.mesh.optimize("Relocate2D")
gmsh.write(output_dir + "/gmsh-native.msh")
"""
mesh = fluentagi.geometry_mesh(
    directory=task_directory,
    code=gmsh_code
)
print(mesh)
if not isinstance(mesh, dict) or not mesh.get("mesh_file"):
    raise RuntimeError("No verified Fluent mesh returned")

settings.file.read_mesh(file_name=mesh["mesh_file"])
settings.mesh.check()
if not settings.setup.models.is_active():
    raise RuntimeError("Physics settings are inactive after reading mesh")

setup = settings.setup
setup.general.solver.type = "pressure-based"
time_options = setup.general.solver.time.allowed_values()
if "unsteady-2nd-order" in time_options:
    setup.general.solver.time = "unsteady-2nd-order"
elif "unsteady-1st-order" in time_options:
    setup.general.solver.time = "unsteady-1st-order"
else:
    print(time_options)
    raise RuntimeError("No supported transient solver option")

setup.models.viscous.model = "laminar"
setup.models.energy.enabled = False
setup.general.operating_conditions.gravity.enable = False

fluids = setup.materials.fluid
if "air" not in fluids.get_object_names():
    raise RuntimeError("Default air material is absent")
material = fluids["air"]
material.density.set_state({"option": "constant", "value": 1.0})
material.viscosity.set_state({"option": "constant", "value": 0.001})

zones = setup.cell_zone_conditions.fluid
zone_names = zones.get_object_names()
if not zone_names:
    raise RuntimeError("No fluid cell zone")
for name in zone_names:
    zones[name].material = "air"

boundaries = setup.boundary_conditions
if "inlet" not in boundaries.velocity_inlet.get_object_names():
    raise RuntimeError("Expected velocity inlet named inlet")
if "outlet" not in boundaries.pressure_outlet.get_object_names():
    raise RuntimeError("Expected pressure outlet named outlet")

momentum = boundaries.velocity_inlet["inlet"].momentum
momentum_state = momentum.get_state()
if "velocity" in momentum_state:
    momentum.velocity = 1.0
elif "velocity_magnitude" in momentum_state:
    momentum.velocity_magnitude = 1.0
else:
    print(momentum_state)
    raise RuntimeError("No verified inlet velocity setting")
boundaries.pressure_outlet["outlet"].momentum.gauge_pressure = 0.0

print({"material": material.get_state()})
print({"inlet": boundaries.velocity_inlet["inlet"].get_state()})
print({"outlet": boundaries.pressure_outlet["outlet"].get_state()})
print({"walls": boundaries.wall.get_state()})
print({"Re": 100.0, "diameter": 0.1, "inlet_velocity": 1.0})

calculation = settings.solution.run_calculation
calculation.transient_controls.time_step_size = 0.005
print({"transient_controls": calculation.transient_controls.get_state()})

settings.file.write_case(file_name=prefix + "_setup.cas.h5")
settings.solution.initialization.hybrid_initialize()
settings.file.write_case_data(file_name=prefix + "_initial.cas.h5")

print({"residual_monitor_settings": settings.solution.monitor.residual.get_state()})
print({
    "frames": 41,
    "steps_per_frame": 30,
    "time_step": 0.005,
    "physical_duration": 6.0,
    "maximum_iterations_per_step": 20
})

try:
    animation = fluentagi.record_animation(
        directory=task_directory,
        field="velocity-magnitude",
        frames=41,
        steps_per_frame=30,
        max_iter_per_step=20
    )
    print({"animation": animation})
finally:
    settings.file.write_case_data(file_name=prefix + "_checkpoint.cas.h5")

exports = fluentagi.export_results(
    directory=task_directory,
    fields=["pressure", "velocity-magnitude"]
)
print({"exports": exports})

for name, result in [("animation", animation), ("exports", exports)]:
    if isinstance(result, dict):
        errors = result.get("errors") or result.get("error")
        failed = result.get("success") is False or result.get("ok") is False
        if errors or failed:
            print({"failed_stage": name, "details": result})
            raise RuntimeError("Inspect returned adapter errors: " + name)

print({"residual_monitor_final": settings.solution.monitor.residual.get_state()})
print("Review actual residual histories and time-step completion in solver output.")
print("Successful execution does not establish convergence or mesh independence.")