import json

import FreeCAD as App

from freecad_mutation_evidence import capture_property_mutation


def version_text():
    return ".".join(str(value) for value in App.Version()[:3])


def box_document(name):
    document = App.newDocument(name)
    body = document.addObject("PartDesign::Body", "Body")
    box = body.newObject("PartDesign::AdditiveBox", "Box")
    box.Length = 10
    box.Width = 10
    box.Height = 10
    document.recompute()
    return document, body, box


def shape_result(case_id, document, feature):
    document.recompute()
    shape = feature.Shape
    return {
        "id": case_id,
        "typeId": feature.TypeId,
        "passed": not shape.isNull() and shape.isValid() and len(shape.Solids) == 1,
        "status": feature.getStatusString(),
        "solids": len(shape.Solids) if not shape.isNull() else 0,
        "faces": len(shape.Faces) if not shape.isNull() else 0,
        "edges": len(shape.Edges) if not shape.isNull() else 0,
        "volume": float(shape.Volume) if not shape.isNull() else 0.0,
    }


def selected_fillet():
    document, body, box = box_document("FilletOracle")
    feature = body.newObject("PartDesign::Fillet", "Fillet")
    feature.Base = (box, ["Edge1"])
    feature.Radius = 1
    mutation = capture_property_mutation(document, feature, "Radius", 0.5)
    result = shape_result("fillet-selected-edge", document, feature)
    result["mutation"] = mutation
    result["selection"] = ["Edge1"]
    App.closeDocument(document.Name)
    return result


def selected_chamfer():
    document, body, box = box_document("ChamferOracle")
    feature = body.newObject("PartDesign::Chamfer", "Chamfer")
    feature.Base = (box, ["Edge1"])
    feature.Size = 1
    mutation = capture_property_mutation(document, feature, "Size", 0.5)
    result = shape_result("chamfer-selected-edge", document, feature)
    result["mutation"] = mutation
    result["selection"] = ["Edge1"]
    App.closeDocument(document.Name)
    return result


def selected_draft():
    document, body, box = box_document("DraftOracle")
    datum_plane = body.newObject("PartDesign::Plane", "DatumPlane")
    datum_plane.AttachmentSupport = [(document.YZ_Plane, "")]
    datum_plane.MapMode = "FlatFace"
    datum_line = body.newObject("PartDesign::Line", "DatumLine")
    datum_line.AttachmentSupport = [(document.X_Axis, "")]
    datum_line.MapMode = "TwoPointLine"
    document.recompute()
    faces = box.Shape.Faces
    candidates = [index for index, face in enumerate(faces) if face.Surface.Axis == App.Vector(0, 0, 1)]
    top_face = max(candidates, key=lambda index: faces[index].CenterOfMass.z)
    feature = body.newObject("PartDesign::Draft", "Draft")
    feature.Base = (box, ["Face{}".format(top_face + 1)])
    feature.NeutralPlane = (datum_plane, [""])
    feature.PullDirection = (datum_line, [""])
    feature.Angle = 45
    feature.Reversed = True
    document.recompute()
    if "Invalid" in feature.State:
        feature.Reversed = False
    mutation = capture_property_mutation(document, feature, "Angle", 30.0)
    result = shape_result("draft-selected-face", document, feature)
    result["mutation"] = mutation
    result["selection"] = ["Face{}".format(top_face + 1)]
    result["reversed"] = bool(feature.Reversed)
    App.closeDocument(document.Name)
    return result


def selected_thickness():
    document, body, box = box_document("ThicknessOracle")
    feature = body.newObject("PartDesign::Thickness", "Thickness")
    feature.Base = (box, ["Face1"])
    feature.Value = 1
    feature.Reversed = True
    feature.Mode = 0
    feature.Join = 0
    mutation = capture_property_mutation(document, feature, "Value", 0.8)
    result = shape_result("thickness-selected-face", document, feature)
    result["mutation"] = mutation
    result["selection"] = ["Face1"]
    result["reversed"] = bool(feature.Reversed)
    result["elementMapSize"] = int(feature.Shape.ElementMapSize)
    App.closeDocument(document.Name)
    return result


cases = [selected_fillet(), selected_chamfer(), selected_draft(), selected_thickness()]
report = {
    "schemaVersion": 1,
    "baselineId": "freecad-1.1.1-partdesign-dressup-oracle",
    "freecadVersion": version_text(),
    "gitCommit": "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d",
    "status": "pass" if all(case["passed"] for case in cases) else "failed",
    "tolerance": 1e-7,
    "cases": cases,
    "summary": {"cases": len(cases), "passed": sum(1 for case in cases if case["passed"])},
}
print("FREECAD_PARTDESIGN_DRESSUP_RESULT=" + json.dumps(report, sort_keys=True, separators=(",", ":")))
