import json
import os

import FreeCAD as App


FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d"
OUTPUT_PATH = os.environ.get("FREECAD_PROPERTY_INTEGERSET_MUTATION_OUTPUT", "")


def snapshot(document, obj, property_name):
    return {
        "value": sorted(int(value) for value in getattr(obj, property_name)),
        "propertyTypeId": obj.getTypeIdOfProperty(property_name),
        "group": obj.getGroupOfProperty(property_name),
        "propertyStatus": [str(item) for item in obj.getPropertyStatus(property_name)],
        "editorMode": [str(item) for item in obj.getEditorMode(property_name)],
        "femMesh": obj.FemMesh.Name if obj.FemMesh else None,
        "propertyNames": list(obj.PropertiesList),
        "shape": {"applicable": hasattr(obj, "Shape")},
        "objectState": [str(item) for item in obj.State],
        "statusString": str(obj.getStatusString()),
        "mustExecute": bool(obj.MustExecute),
        "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects],
    }


def run_case(object_type_id, object_name, property_name, initial, edited):
    document = App.newDocument("PropertyIntegerSetMutation" + object_name)
    try:
        obj = document.addObject(object_type_id, object_name)
        setattr(obj, property_name, initial)
        initial_recompute = bool(document.recompute())
        before = snapshot(document, obj, property_name)
        setattr(obj, property_name, edited)
        touched_after_edit = snapshot(document, obj, property_name)
        edit_recompute = bool(document.recompute())
        after_edit = snapshot(document, obj, property_name)
        setattr(obj, property_name, initial)
        touched_after_restore = snapshot(document, obj, property_name)
        restore_recompute = bool(document.recompute())
        restored = snapshot(document, obj, property_name)
        neighbors = lambda value: {key: value[key] for key in ["femMesh", "propertyNames"]}
        return {
            "objectTypeId": object_type_id,
            "objectName": object_name,
            "propertyName": property_name,
            "recompute": {"initial": initial_recompute, "edit": edit_recompute, "restore": restore_recompute},
            "before": before,
            "touchedAfterEdit": touched_after_edit,
            "edited": after_edit,
            "touchedAfterRestore": touched_after_restore,
            "restored": restored,
            "neighborsPreserved": neighbors(before) == neighbors(after_edit) == neighbors(restored),
            "valueRestored": before["value"] == restored["value"],
            "semanticStateRestored": before == restored,
            "objectsRestored": before["objectSet"] == restored["objectSet"],
        }
    finally:
        App.closeDocument(document.Name)


cases = [
    run_case("Fem::FemSetNodesObject", "NodesProbe", "Nodes", [1, 3], [5, 2, 5]),
    run_case("Fem::FemSetElementNodesObject", "ElementsProbe", "Elements", [4, 10], [-1, 8, 8]),
]
report = {"schemaVersion": 1, "status": "pass", "baselineId": "freecad-1.1.1-property-integerset-mutation", "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), "gitCommit": FREECAD_COMMIT, "propertyType": "App::PropertyIntegerSet", "caseCount": len(cases), "cases": cases}
if not OUTPUT_PATH:
    raise RuntimeError("FREECAD_PROPERTY_INTEGERSET_MUTATION_OUTPUT is required")
with open(OUTPUT_PATH, "w", encoding="utf-8") as handle:
    json.dump(report, handle, indent=2, sort_keys=True)
    handle.write("\n")
print("FREECAD_PROPERTY_INTEGERSET_MUTATION_RESULT=" + json.dumps({"status": report["status"], "caseCount": report["caseCount"]}, sort_keys=True))

