# Use the existing connected PyFluent variable solver.
task_directory = r"C:\Users\13977\AppData\Local\FluentAGI\data\runs\20261025-223856-955f7c"

geometry_code = r"""
gmsh.model.add("structured_unstructured_comparison")
occ = gmsh.model.occ
surfaces = []
channel_edges = []
for index in range(2):
    y0 = 0.06 * index
    points = [
        occ.addPoint(x, y0 + y, 0.0, 0.005)
        for x, y in [(0.0, 0.0), (0.2, 0.0), (0.2, 0.04), (0.0, 0.04)]
    ]
    edges = [
        occ.addLine(points[i], points[(i + 1) % 4])
        for i in range(4)
    ]
    loop = occ.addCurveLoop(edges)
    surfaces.append(occ.addPlaneSurface([loop]))
    channel_edges.append(edges)
occ.synchronize()

for i, edge in enumerate(channel_edges[0]):
    gmsh.model.mesh.setTransfiniteCurve(edge, 41 if i % 2 == 0 else 9)
gmsh.model.mesh.setTransfiniteSurface(surfaces[0])
gmsh.model.mesh.setRecombine(2, surfaces[0])

for index, suffix in enumerate(["a", "b"]):
    edges = channel_edges[index]
    groups = [
        ([edges[3]], "inlet-" + suffix),
        ([edges[1]], "outlet-" + suffix),
        ([edges[0], edges[2]], "wall-" + suffix)
    ]
    for entities, name in groups:
        tag = gmsh.model.addPhysicalGroup(1, entities)
        gmsh.model.setPhysicalName(1, tag, name)
tag = gmsh.model.addPhysicalGroup(2, surfaces)
gmsh.model.setPhysicalName(2, tag, "fluid")

for name, value in [
    ("Mesh.ElementOrder", 1),
    ("Mesh.Algorithm", 6),
    ("Mesh.RecombineAll", 0),
    ("Mesh.MeshSizeMin", 0.005),
    ("Mesh.MeshSizeMax", 0.005),
    ("Mesh.Smoothing", 3)
]:
    gmsh.option.setNumber(name, value)

gmsh.write(output_dir + "/comparison.step")
gmsh.model.mesh.generate(2)

counts = []
for index, surface in enumerate(surfaces):
    types, element_tags, node_tags = gmsh.model.mesh.getElements(2, surface)
    expected_type = 3 if index == 0 else 2
    if any(t != expected_type for t in types):
        raise RuntimeError("Unexpected element type in comparison channel.")
    count = sum(len(tags) for tags in element_tags)
    if count == 0:
        raise RuntimeError("Empty comparison channel.")
    counts.append(count)
if counts[0] != 320:
    raise RuntimeError("Structured channel must contain exactly 320 quadrilaterals.")
if sum(counts) > 2000000:
    raise RuntimeError("Configured mesh_cell_limit exceeded.")
print({
    "A": {"quadrilaterals": counts[0], "nx": 40, "ny": 8},
    "B": {"triangles": counts[1], "target_size_m": 0.005},
    "total_cells": sum(counts),
    "A_y_range_m": [0.0, 0.04],
    "B_y_range_m": [0.06, 0.10]
})
gmsh.write(output_dir + "/gmsh-native.msh")
"""

def inspect_export_errors(value, location="exports"):
    errors = []
    if isinstance(value, dict):
        for key, item in value.items():
            child = location + "." + str(key)
            if key in ["error", "errors"] and item:
                errors.append({"location": child, "detail": item})
            elif key == "success" and item is False:
                errors.append({"location": child, "detail": False})
            elif key == "status" and isinstance(item, str) and item in ["error", "failed"]:
                errors.append({"location": child, "detail": item})
            elif isinstance(item, (dict, list, tuple)):
                errors.extend(inspect_export_errors(item, child))
    elif isinstance(value, (list, tuple)):
        for index, item in enumerate(value):
            errors.extend(inspect_export_errors(item, location + "." + str(index)))
    return errors

try:
    print(fluentagi.backup_loaded(directory=task_directory))
    mesh = fluentagi.geometry_mesh(
        directory=task_directory,
        code=geometry_code
    )
    print(mesh)
    if not isinstance(mesh, dict) or not mesh.get("mesh_file"):
        raise RuntimeError("No converted Fluent mesh was returned.")

    solver.settings.file.read_mesh(file_name=mesh["mesh_file"])
    print(solver.settings.mesh.check())
    print(fluentagi.stage(
        directory=task_directory,
        name="comparison_mesh_imported",
        mesh_file=mesh["mesh_file"]
    ))

    viscous = solver.settings.setup.models.viscous.model
    if not viscous.is_active():
        raise RuntimeError("Viscous model setting is inactive after mesh import.")
    viscous.set_state("laminar")
    solver.settings.setup.general.solver.time.set_state("steady")
    energy = solver.settings.setup.models.energy.enabled
    if energy.is_active():
        energy.set_state(False)

    fluids = solver.settings.setup.cell_zone_conditions.fluid
    fluid_names = fluids.get_object_names()
    if not fluid_names:
        raise RuntimeError("No fluid cell zones were imported.")
    for name in fluid_names:
        fluids[name].general.material.set_state("air")

    boundary = solver.settings.setup.boundary_conditions
    inlet_names = boundary.velocity_inlet.get_object_names()
    outlet_names = boundary.pressure_outlet.get_object_names()
    for suffix in ["a", "b"]:
        inlet_name = "inlet-" + suffix
        outlet_name = "outlet-" + suffix
        if inlet_name not in inlet_names or outlet_name not in outlet_names:
            raise RuntimeError("Missing comparison inlet or outlet: " + suffix)
        boundary.velocity_inlet[inlet_name].momentum.velocity.value.set_state(0.1)
        boundary.pressure_outlet[outlet_name].momentum.gauge_pressure.value.set_state(0.0)

    readback = {
        "viscous_model": viscous.get_state(),
        "time_mode": solver.settings.setup.general.solver.time.get_state(),
        "fluids": fluids.get_state(),
        "walls": boundary.wall.get_state(),
        "boundaries": {}
    }
    for suffix in ["a", "b"]:
        readback["boundaries"][suffix] = {
            "velocity": boundary.velocity_inlet[
                "inlet-" + suffix
            ].momentum.velocity.value.get_state(),
            "gauge_pressure": boundary.pressure_outlet[
                "outlet-" + suffix
            ].momentum.gauge_pressure.value.get_state()
        }
    print(readback)
    print(fluentagi.stage(
        directory=task_directory,
        name="comparison_physics_configured",
        maximum_iterations=150
    ))

    solver.settings.solution.initialization.hybrid_initialize()
    print(fluentagi.stage(
        directory=task_directory,
        name="comparison_initialization_completed"
    ))

    solver.settings.solution.run_calculation.iterate(iter_count=150)
    print(fluentagi.stage(
        directory=task_directory,
        name="comparison_iteration_call_completed",
        maximum_requested_iterations=150,
        convergence_verified=False
    ))

    exports = fluentagi.export_results(
        directory=task_directory,
        fields=["pressure", "velocity-magnitude"]
    )
    print(exports)
    export_errors = inspect_export_errors(exports)
    if exports is None:
        export_errors.append({"detail": "No export receipt returned."})

    print(fluentagi.write_json(
        directory=task_directory,
        name="assessment.json",
        data={
            "comparison": {
                "A": {
                    "dimensions_m": [0.2, 0.04],
                    "mesh": "structured quadrilateral",
                    "nx": 40,
                    "ny": 8,
                    "cells": 320,
                    "y_range_m": [0.0, 0.04]
                },
                "B": {
                    "dimensions_m": [0.2, 0.04],
                    "mesh": "unstructured triangle",
                    "target_size_m": 0.005,
                    "y_range_m": [0.06, 0.10],
                    "cell_count_evidence": "Geometry worker output and mesh receipt"
                }
            },
            "mesh_file": mesh["mesh_file"],
            "physics_readback": readback,
            "maximum_requested_iterations": 150,
            "iteration_call_completed": True,
            "convergence_verified": False,
            "mass_balance_verified": False,
            "exports": exports,
            "export_errors": export_errors,
            "review_status": "needs-review",
            "interpretation": "Teaching comparison; equal nominal mesh size does not imply equal cell count or demonstrated mesh independence."
        }
    ))
    if export_errors:
        raise RuntimeError("Export reported errors; preserve the current solution without recomputing.")
except Exception as error:
    print({"status": "failed", "error": str(error)})
    print(fluentagi.inspect_execution(directory=task_directory))
    raise