# 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", [])
    print(label + "_CHILDREN", children)
    print(label + "_COMMANDS", commands)
    print(label + "_QUERIES", getattr(obj, "query_names", []))
    for name in commands:
        command = getattr(obj, name)
        print(label + "_ARGUMENTS", name, getattr(command, "argument_names", []))

print("CURRENT_MODEL_ACTIVE", s.setup.models.is_active())
if s.setup.models.is_active():
    print("CURRENT_SOLVER", s.setup.general.solver.get_state())
    print("CURRENT_FLUID_ZONES", s.setup.cell_zone_conditions.fluid.get_object_names())
    s.file.write_case_data(
        file_name=task_directory + r"\before_front_wing_mesh_repair.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)
]:
    upper = []
    lower = []
    a = angle * math.pi / 180.0
    for i in range(33):
        u = 0.5 * (1.0 - math.cos(math.pi * i / 32))
        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 == 32:
            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 = occ.addSpline(
        [upper[-1]] + lower[1:-1][::-1] + [upper[0]]
    )
    face = occ.addPlaneSurface([occ.addWire([top, bottom])])
    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]:
    parts.append((3, occ.addBox(-0.02, 0.10, z, 0.50, 0.24, 0.008)))
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", 40)
near = gmsh.model.mesh.field.add("Threshold")
gmsh.model.mesh.field.setNumber(near, "InField", distance)
gmsh.model.mesh.field.setNumber(near, "DistMin", 0.008)
gmsh.model.mesh.field.setNumber(near, "DistMax", 0.14)
wake = gmsh.model.mesh.field.add("Box")
for name, value in [
    ("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),
    ("Mesh.Optimize", 1)
]:
    gmsh.option.setNumber(name, value)
gmsh.write(output_dir + "/front-wing.step")
accepted = False
for attempt in range(4):
    factor = 1.30 ** attempt
    fine = 0.014 * factor
    far = 0.20 * factor
    trail = 0.060 * factor
    gmsh.model.mesh.field.setNumber(near, "SizeMin", fine)
    gmsh.model.mesh.field.setNumber(near, "SizeMax", far)
    gmsh.model.mesh.field.setNumber(wake, "VIn", trail)
    gmsh.model.mesh.field.setNumber(wake, "VOut", far)
    gmsh.model.mesh.generate(3)
    element_types, element_tags, node_tags = gmsh.model.mesh.getElements(3)
    count = sum([len(tags) for tags in element_tags])
    print("MESH_BUDGET", attempt, count, fine, trail, far)
    if count > 0 and count <= 180000:
        accepted = True
        break
    gmsh.model.mesh.clear()
if not accepted:
    raise RuntimeError("Mesh budget exceeded after controlled coarsening")
print("FINAL_VOLUME_CELLS", count)
print("WING_CAD_SURFACES", wing_faces)
print("GROUND_CAD_SURFACES", ground_faces)
print("FINAL_LOCAL_SIZES", fine, trail, far)
"""

mesh = checked(
    "REPAIRED_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("Loaded mesh model is inactive")

s.file.write_case(
    file_name=task_directory + r"\front_wing_repaired_mesh.cas.h5"
)

bc = s.setup.boundary_conditions
for label, container in [
    ("WALL_ZONES", bc.wall),
    ("INLET_ZONES", bc.velocity_inlet),
    ("OUTLET_ZONES", bc.pressure_outlet),
]:
    print(label, container.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))

for name in bc.wall.get_object_names():
    print("WALL_STATE", name, bc.wall[name].get_state())
    describe("WALL_MOMENTUM", bc.wall[name].momentum)
    break

reports = s.solution.report_definitions
describe("REPORT_DEFINITIONS", reports)
for name in getattr(reports, "child_names", []):
    if any(word in name for word in ["force", "lift", "drag"]):
        describe("REPORT_" + name, getattr(reports, 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))

print("DESIGN", {
    "velocity": 30.0,
    "span": 1.2,
    "main_chord": 0.32,
    "flap_chord": 0.14,
    "main_angle": 8.0,
    "flap_angle": 20.0,
    "endplate_clearance": 0.10,
    "maximum_volume_cells": 180000,
})
print("STAGE", "mesh_repair_and_native_interface_readback")