# Use the existing connected PyFluent variable solver.
task_directory = r"C:\Users\13977\AppData\Local\FluentAGI\data\runs\20261018-142547-90d0a4"
s = solver.settings

def checked(label, result):
    print(label, result)
    if isinstance(result, dict):
        if result.get("status") in ("error", "failed", "needs_review"):
            raise RuntimeError(str(result))
        if result.get("error") or result.get("errors"):
            raise RuntimeError(str(result))
    return result

def describe(label, obj):
    print(label + "_ACTIVE", obj.is_active())
    children = getattr(obj, "child_names", [])
    commands = getattr(obj, "command_names", [])
    queries = getattr(obj, "query_names", [])
    print(label + "_CHILDREN", children)
    print(label + "_COMMANDS", commands)
    print(label + "_QUERIES", queries)
    for name in commands:
        command = getattr(obj, name)
        print(label + "_ARGUMENTS", name, getattr(command, "argument_names", []))

if s.setup.models.is_active():
    s.file.write_case_data(
        file_name=task_directory + r"\before_front_wing.cas.h5"
    )

code = """
gmsh.model.add("front_wing")
occ = gmsh.model.occ
domain = occ.addBox(-1.0, 0.0, -1.2, 4.0, 1.2, 2.4)
parts = []
for chord, x0, y0, angle in [
    (0.32, 0.0, 0.15, 8.0),
    (0.14, 0.30, 0.215, 20.0)
]:
    n = 40
    upper = []
    lower = []
    a = angle * math.pi / 180.0
    for i in range(n + 1):
        u = 0.5 * (1.0 - math.cos(math.pi * i / n))
        t = 5.0 * 0.12 * chord * (
            0.2969 * math.sqrt(u) - 0.1260 * u
            - 0.3516 * u**2 + 0.2843 * u**3 - 0.1036 * u**4
        )
        if i == 0 or i == n:
            t = 0.0
        for points, sign in [(upper, 1.0), (lower, -1.0)]:
            x = x0 + chord * u * math.cos(a) - sign * t * math.sin(a)
            y = y0 + chord * u * math.sin(a) + sign * t * math.cos(a)
            points.append(occ.addPoint(x, y, -0.60))
    top = occ.addSpline(upper)
    bottom_points = [upper[-1]] + lower[1:-1][::-1] + [upper[0]]
    bottom = occ.addSpline(bottom_points)
    wire = occ.addWire([top, bottom])
    face = occ.addPlaneSurface([wire])
    extrusion = occ.extrude([(2, face)], 0.0, 0.0, 1.20)
    for dim, tag in extrusion:
        if dim == 3:
            parts.append((dim, tag))
for z in [-0.608, 0.600]:
    plate = occ.addBox(-0.02, 0.10, z, 0.50, 0.24, 0.008)
    parts.append((3, plate))
body, mapping = occ.fuse([parts[0]], parts[1:])
fluid, mapping = occ.cut([(3, domain)], body)
occ.removeAllDuplicates()
occ.synchronize()
volumes = [tag for dim, tag in gmsh.model.getEntities(3)]
if len(volumes) != 1:
    raise RuntimeError("Expected one connected fluid volume")
gmsh.model.addPhysicalGroup(3, volumes, name="fluid")
inlet = []
outlet = []
walls = []
wing_faces = []
ground_faces = []
for dim, tag in gmsh.model.getBoundary(
    [(3, volumes[0])], oriented=False, recursive=False
):
    b = gmsh.model.getBoundingBox(dim, tag)
    if abs(b[0] + 1.0) < 1e-6 and abs(b[3] + 1.0) < 1e-6:
        inlet.append(tag)
    elif abs(b[0] - 3.0) < 1e-6 and abs(b[3] - 3.0) < 1e-6:
        outlet.append(tag)
    else:
        walls.append(tag)
        if abs(b[1]) < 1e-6 and abs(b[4]) < 1e-6:
            ground_faces.append(tag)
        elif b[0] > -0.03 and b[3] < 0.49 and b[1] > 0.09:
            if b[2] > -0.62 and b[5] < 0.62:
                wing_faces.append(tag)
if not inlet or not outlet or not wing_faces or not ground_faces:
    raise RuntimeError("Boundary classification failed")
for name, tags in [("inlet", inlet), ("outlet", outlet), ("walls", walls)]:
    gmsh.model.addPhysicalGroup(2, tags, name=name)
distance = gmsh.model.mesh.field.add("Distance")
gmsh.model.mesh.field.setNumbers(distance, "FacesList", wing_faces)
gmsh.model.mesh.field.setNumber(distance, "Sampling", 60)
near = gmsh.model.mesh.field.add("Threshold")
for name, value in [
    ("InField", distance), ("SizeMin", 0.008), ("SizeMax", 0.15),
    ("DistMin", 0.012), ("DistMax", 0.18)
]:
    gmsh.model.mesh.field.setNumber(near, name, value)
wake = gmsh.model.mesh.field.add("Box")
for name, value in [
    ("VIn", 0.04), ("VOut", 0.15),
    ("XMin", 0.25), ("XMax", 1.6),
    ("YMin", 0.07), ("YMax", 0.45),
    ("ZMin", -0.72), ("ZMax", 0.72), ("Thickness", 0.12)
]:
    gmsh.model.mesh.field.setNumber(wake, name, value)
minimum = gmsh.model.mesh.field.add("Min")
gmsh.model.mesh.field.setNumbers(minimum, "FieldsList", [near, wake])
gmsh.model.mesh.field.setAsBackgroundMesh(minimum)
for name, value in [
    ("Mesh.MeshSizeFromPoints", 0),
    ("Mesh.MeshSizeFromCurvature", 0),
    ("Mesh.MeshSizeExtendFromBoundary", 0),
    ("Mesh.ElementOrder", 1),
    ("Mesh.Algorithm3D", 1)
]:
    gmsh.option.setNumber(name, value)
gmsh.write(output_dir + "/front-wing.step")
gmsh.model.mesh.generate(3)
print("WING_CAD_SURFACES", wing_faces)
print("GROUND_CAD_SURFACES", ground_faces)
print("REFINEMENT", 0.008, 0.04, 0.15)
"""

mesh = checked(
    "FRONT_WING_MESH",
    fluentagi.geometry_mesh(directory=task_directory, code=code),
)
if not isinstance(mesh, dict) or not mesh.get("mesh_file"):
    raise RuntimeError("Missing converted Fluent mesh")
s.file.read_mesh(file_name=mesh["mesh_file"])
s.mesh.check()

if not s.setup.models.is_active():
    raise RuntimeError("Mesh model is inactive")

print("WALL_ZONE_NAMES", s.setup.boundary_conditions.wall.get_object_names())
print("INLET_ZONE_NAMES", s.setup.boundary_conditions.velocity_inlet.get_object_names())
print("OUTLET_ZONE_NAMES", s.setup.boundary_conditions.pressure_outlet.get_object_names())

describe("MESH", s.mesh)
for name in getattr(s.mesh, "child_names", []):
    if "zone" in name or "modify" in name:
        describe("MESH_" + name, getattr(s.mesh, name))

walls = s.setup.boundary_conditions.wall
for name in walls.get_object_names():
    wall = walls[name]
    print("WALL_STATE", name, wall.get_state())
    describe("WALL_MOMENTUM", wall.momentum)
    break

describe("REPORT_DEFINITIONS", s.solution.report_definitions)
for name in getattr(s.solution.report_definitions, "child_names", []):
    if "force" in name or "lift" in name or "drag" in name:
        describe("REPORT_" + name, getattr(s.solution.report_definitions, name))

graphics = s.results.graphics
describe("GRAPHICS", graphics)
for name in getattr(graphics, "child_names", []):
    if "path" in name or "stream" in name:
        describe("GRAPHICS_" + name, getattr(graphics, name))

s.file.write_case(
    file_name=task_directory + r"\front_wing_mesh_and_interfaces.cas.h5"
)
print("DESIGN", {
    "velocity": 30.0,
    "span": 1.2,
    "main_chord": 0.32,
    "flap_chord": 0.14,
    "main_angle": 8.0,
    "flap_angle": 20.0,
    "minimum_clearance": 0.10,
})
print("STAGE", "mesh_and_native_interface_readback")