import json

import FreeCAD as App


FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d"


def quantity_snapshot(value):
    return {
        "raw": str(value),
        "numeric": round(float(value.Value), 9),
        "unit": str(value.Unit),
    }


def object_snapshot(obj):
    return {
        "name": obj.Name,
        "typeId": obj.TypeId,
        "state": [str(item) for item in obj.State],
        "status": obj.getStatusString(),
    }


def element_snapshot(obj, sub_elements):
    entries = []
    for sub_element in sub_elements:
        shape = obj.Shape if not sub_element else obj.getSubObject(sub_element)
        entries.append({
            "object": obj.Name,
            "subElement": sub_element,
            "shapeType": shape.ShapeType,
            "shapeNull": bool(shape.isNull()),
            "shapeValid": bool(shape.isValid()),
            "area": round(float(shape.Area), 9),
            "faces": len(shape.Faces),
            "edges": len(shape.Edges),
            "vertices": len(shape.Vertexes),
        })
    return entries


def run():
    document = App.newDocument("PropertyAreaSuccess")
    try:
        box = document.addObject("Part::Box", "AreaBox")
        box.Length = 10
        box.Width = 5
        box.Height = 2
        cylinder = document.addObject("Part::Cylinder", "AreaCylinder")
        cylinder.Radius = 3
        cylinder.Height = 4
        sphere = document.addObject("Part::Sphere", "AreaSphere")
        sphere.Radius = 2
        measure = document.addObject("Measure::MeasureArea", "AreaProbe")
        document.recompute()

        cases = []

        def capture(case_id, requested):
            if requested is not None:
                measure.Elements = requested
                document.recompute()
            references = [] if requested is None else [
                (obj, list(sub_elements)) for obj, sub_elements in requested
            ]
            elements = [
                entry
                for obj, sub_elements in references
                for entry in element_snapshot(obj, sub_elements)
            ]
            expected_area = round(sum(entry["area"] for entry in elements), 9)
            cases.append({
                "id": case_id,
                "elements": elements,
                "expectedArea": expected_area,
                "value": quantity_snapshot(measure.Area),
                "propertyStatus": [str(item) for item in measure.getPropertyStatus("Area")],
                "editorMode": [str(item) for item in measure.getEditorMode("Area")],
                "elementsTypeId": measure.getTypeIdOfProperty("Elements"),
                "areaTypeId": measure.getTypeIdOfProperty("Area"),
                "object": object_snapshot(measure),
                "shape": {"applicable": hasattr(measure, "Shape")},
            })

        capture("empty-default", None)
        capture("planar-face", [(box, ["Face1"])])
        capture("cylindrical-face", [(cylinder, ["Face1"])])
        capture("surface-face", [(sphere, ["Face1"])])
        capture("solid-volume", [(box, [""])])
        capture("multi-element-sum", [(box, ["Face1", "Face2"]), (cylinder, ["Face1"])])

        return {
            "schemaVersion": 1,
            "status": "pass",
            "baselineId": "freecad-1.1.1-property-area-success",
            "freecadVersion": ".".join(str(value) for value in App.Version()[:3]),
            "gitCommit": FREECAD_COMMIT,
            "object": {"name": measure.Name, "typeId": measure.TypeId},
            "property": {"name": "Area", "typeId": measure.getTypeIdOfProperty("Area"), "group": measure.getGroupOfProperty("Area")},
            "input": {"name": "Elements", "typeId": measure.getTypeIdOfProperty("Elements"), "group": measure.getGroupOfProperty("Elements")},
            "sources": [object_snapshot(source) for source in [box, cylinder, sphere]],
            "cases": cases,
            "diagnostics": {"exception": None, "documentObjectCount": len(document.Objects)},
        }
    finally:
        App.closeDocument(document.Name)


print("FREECAD_PROPERTY_AREA_SUCCESS_RESULT=" + json.dumps(run(), sort_keys=True))
